Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
checkAttr.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 /**
7  * Checking application accesses
8  * @class CheckAttr
9  * @brief Check application accesses when importing definition
10  * @see ErrorCodeATTR
11  */
12 class CheckAttr extends CheckData
13 {
14  /**
15  * Type of import line : 'ATTR', 'PARAM', 'MODATTR', etc.
16  * @var string
17  */
18  private $lineType = '';
19  /**
20  * @var StructAttribute
21  */
22  private $structAttr = null;
23  private $types = array(
24  "text",
25  "longtext",
26  "image",
27  "file",
28  "frame",
29  "enum",
30  "date",
31  "integer",
32  "int",
33  "double",
34  "money",
35  "password",
36  "ifile",
37  "xml",
38  "thesaurus",
39  "tab",
40  "time",
41  "timestamp",
42  "array",
43  "color",
44  "menu",
45  "action",
46  "docid",
47  "htmltext",
48  "account"
49  );
50 
51  private $noValueTypes = array(
52  "frame",
53  "tab",
54  "menu",
55  "action",
56  "array"
57  );
58  private $visibilities = array(
59  'I',
60  'H',
61  'R',
62  'W',
63  'O',
64  'S',
65  'U'
66  );
67 
68  private $yesno = array(
69  'y',
70  'n'
71  );
72  private $postgreSqlWords = array(
73  'all',
74  'analyse',
75  'analyze',
76  'and',
77  'any',
78  'array',
79  'as',
80  'asc',
81  'asymmetric',
82  'both',
83  'case',
84  'cast',
85  'check',
86  'collate',
87  'column',
88  'constraint',
89  'create',
90  'current_date',
91  'current_role',
92  'current_time',
93  'current_timestamp',
94  'current_user',
95  'default',
96  'deferrable',
97  'desc',
98  'distinct',
99  'do',
100  'else',
101  'end',
102  'except',
103  'false',
104  'for',
105  'foreign',
106  'from',
107  'grant',
108  'group',
109  'having',
110  'in',
111  'initially',
112  'intersect',
113  'into',
114  'leading',
115  'limit',
116  'localtime',
117  'localtimestamp',
118  'new',
119  'not',
120  'null',
121  'off',
122  'offset',
123  'old',
124  'on',
125  'only',
126  'or',
127  'order',
128  'placing',
129  'primary',
130  'references',
131  'returning',
132  'select',
133  'session_user',
134  'some',
135  'symmetric',
136  'table',
137  'then',
138  'to',
139  'trailing',
140  'true',
141  'union',
142  'unique',
143  'user',
144  'using',
145  'when',
146  'where',
147  'with'
148  );
149  /**
150  * the attribute identifier
151  * @var string
152  */
153  private $attrid;
154  /**
155  * analyze an attribute structure
156  * @param array $data
157  * @param mixed $extra
158  * @return CheckAttr
159  */
160  /**
161  * @var Doc
162  */
163  private $doc = null;
164  /**
165  * true if check MODATTR
166  * @var bool
167  */
168  private $isModAttr = false;
169 
170  public function check(array $data, &$extra = null)
171  {
172  $this->lineType = $data[0];
173  $this->structAttr = new StructAttribute($data);
174  $this->doc = $extra;
175  $this->attrid = strtolower($this->structAttr->id);
176  $this->isModAttr = (strtolower($data[0]) == "modattr");
177  $this->checkId();
178  $this->checkSet();
179  $this->checkType();
180  $this->checkOrder();
181  $this->checkVisibility();
182  $this->checkIsAbstract();
183  $this->checkIsTitle();
184  $this->checkIsNeeded();
185  if ($this->checkPhpFile()) {
186  $this->checkPhpFunctionOrMethod();
187  $this->checkEnum();
188  }
189  $this->checkPhpConstraint();
190  $this->checkOptions();
191  return $this;
192  }
193  /**
194  * test syntax for document's identifier
195  * @return void
196  */
197  private function checkId()
198  {
199  if (empty($this->attrid)) {
200  $this->addError(ErrorCode::getError('ATTR0102'));
201  } elseif (!$this->checkAttrSyntax($this->attrid)) {
202  $this->addError(ErrorCode::getError('ATTR0100', $this->attrid));
203  } else {
204  if (in_array($this->attrid, $this->postgreSqlWords)) {
205  $this->addError(ErrorCode::getError('ATTR0101', $this->attrid));
206  } else {
207  $doc = new Doc();
208  if (in_array($this->attrid, $doc->fields)) {
209  $this->addError(ErrorCode::getError('ATTR0103', $this->attrid));
210  }
211  }
212  }
213  }
214  /**
215  * test syntax for document's identifier
216  * @return void
217  */
218  private function checkSet()
219  {
220  $setId = strtolower($this->structAttr->setid);
221  if ($setId && ($this->attrid == $setId)) {
222  $this->addError(ErrorCode::getError('ATTR0202', $setId, $this->attrid));
223  }
224  if ($this->isNodeNeedSet()) {
225  if (empty($setId)) {
226  $this->addError(ErrorCode::getError('ATTR0201', $this->attrid));
227  } elseif (!$this->checkAttrSyntax($setId)) {
228  $this->addError(ErrorCode::getError('ATTR0200', $setId, $this->attrid));
229  }
230  } elseif ($setId) {
231  if (!$this->checkAttrSyntax($setId)) {
232  $this->addError(ErrorCode::getError('ATTR0200', $setId, $this->attrid));
233  } else {
234  if ($this->getType() == 'tab') {
235  $this->addError(ErrorCode::getError('ATTR0206', $setId, $this->attrid));
236  }
237  }
238  }
239  }
240  /**
241  * test attribute type is a recognized type
242  * @return void
243  */
244  private function checkType()
245  {
246  $type = $this->structAttr->type;
247  if (!$type) {
248  if (!$this->isModAttr) {
249  $this->addError(ErrorCode::getError('ATTR0600', $this->attrid));
250  } else {
251  $this->checkModAttrType();
252  }
253  } elseif (!in_array($type, $this->types)) {
254  $basicType = $this->getType();
255  if (!$basicType) {
256  $this->addError(ErrorCode::getError('ATTR0602', $type, $this->attrid));
257  } elseif (!in_array($basicType, $this->types)) {
258  $this->addError(ErrorCode::getError('ATTR0601', $basicType, $this->attrid, implode(', ', $this->types)));
259  } else {
260  $format = $this->getFormat();
261  if ($format) {
262  if (in_array($basicType, array(
263  'text',
264  'int',
265  'double',
266  'money',
267  'longtext'
268  ))) {
269  $a = @sprintf($format, 123);
270  if ($a === false) {
271  $this->addError(ErrorCode::getError('ATTR0603', $format, $this->attrid));
272  }
273  }
274  }
275  if ($this->isModAttr) {
276  $this->checkModAttrType();
277  }
278  }
279  } else {
280  if ($this->isModAttr) {
281  $this->checkModAttrType();
282  }
283  }
284  }
285  /**
286  * Verify id modattr of enum if compatible whith origin
287  */
288  private function checkModAttrType()
289  {
290  $type = $this->structAttr->type;
291 
292  $basicType = $this->getType();
293  $originAttr = $this->getOriginAttr($this->attrid, $this->doc->fromid, $this->doc->id);
294  if ($originAttr) {
295  $originType = $originAttr["type"];
296  $basicOriginType = $this->getType($originType);
297  if ($basicOriginType == "enum") {
298  if (trim($this->structAttr->phpfunc) != '') {
299  $this->addError(ErrorCode::getError('ATTR0606', $this->attrid, $this->doc->name));
300  }
301  }
302  if (!$type) return;
303  if (!$this->isCompatibleModType($basicOriginType, $basicType)) {
304 
305  $this->addError(ErrorCode::getError('ATTR0604', $this->attrid, $this->doc->name, $type, $originType));
306  }
307  } else {
308  $this->addError(ErrorCode::getError('ATTR0605', $this->attrid, $this->doc->name));
309  }
310  }
311 
312  private function getOriginAttr($attrid, $fromid, $docid)
313  {
314  $sqlPattern = <<< 'SQL'
315  select * from docattr where docid in (
316  with recursive adocfam(id, fromid, famname) as (
317  select docfam.id, docfam.fromid, docfam.name as famname from docfam where docfam.id=%d or docfam.id=%d
318  union
319  select docfam.id, docfam.fromid, docfam.name as famname from docfam, adocfam where docfam.id = adocfam.fromid
320  ) select id from adocfam
321  ) and id='%s' order by docid desc;
322 SQL;
323 
324  $attrid = pg_escape_string($attrid);
325  $sql = sprintf($sqlPattern, $docid, $fromid, $attrid);
326  simpleQuery('', $sql, $r);
327  if (count($r) > 0) {
328  return $r[0];
329  }
330  return null;
331  }
332 
333  private function isCompatibleModType($typeA, $typeB)
334  {
335  if ($typeA == $typeB) return true;
336  $compatibleText = array(
337  'text',
338  'htmltext',
339  'longtext'
340  );
341  if (in_array($typeA, $compatibleText) && in_array($typeB, $compatibleText)) return true;
342  $compatibleNumbers = array(
343  'double',
344  'money'
345  );
346  if (in_array($typeA, $compatibleNumbers) && in_array($typeB, $compatibleNumbers)) return true;
347  $compatibleRelation = array(
348  'docid',
349  'account',
350  'thesaurus'
351  );
352  if (in_array($typeA, $compatibleRelation) && in_array($typeB, $compatibleRelation)) return true;
353  return false;
354  }
355  /**
356  * test syntax order
357  * must be an integer
358  * @return void
359  */
360  private function checkOrder()
361  {
362  $order = $this->structAttr->order;
363 
364  if ($this->isNodeNeedOrder() && empty($order)) {
365  $this->addError(ErrorCode::getError('ATTR0702', $this->attrid));
366  } elseif ($order) {
367  if (!is_numeric($order)) {
368  if ($order === \dcp\FamilyAbsoluteOrder::firstOrder || $order === \dcp\FamilyAbsoluteOrder::autoOrder) {
369  return;
370  }
371  if (!$this->checkAttrSyntax($order)) {
372  $this->addError(ErrorCode::getError('ATTR0700', $order, $this->attrid));
373  }
374  }
375  }
376  }
377  /**
378  * test syntax order
379  * must be an integer
380  * @return void
381  */
382  private function checkVisibility()
383  {
384  $vis = $this->structAttr->visibility;
385  if (empty($vis)) {
386  if (!$this->isModAttr) {
387  $this->addError(ErrorCode::getError('ATTR0800', $this->attrid));
388  }
389  } elseif (!in_array($vis, $this->visibilities)) {
390  $this->addError(ErrorCode::getError('ATTR0801', $vis, $this->attrid, implode(',', $this->visibilities)));
391  } else {
392  $type = $this->getType();
393  if ($vis == "U" && $type && ($type != "array")) {
394  $this->addError(ErrorCode::getError('ATTR0802', $this->attrid));
395  }
396  }
397  }
398 
399  private function checkIsAbstract()
400  {
401  $isAbstract = strtolower($this->structAttr->isabstract);
402  if ($isAbstract) {
403  if (!in_array($isAbstract, $this->yesno)) {
404  $this->addError(ErrorCode::getError('ATTR0500', $isAbstract, $this->attrid));
405  } elseif ($isAbstract == 'y' && (!$this->isNodeHasValue())) {
406  $this->addError(ErrorCode::getError('ATTR0501', $this->attrid));
407  }
408  }
409  }
410 
411  private function checkIsTitle()
412  {
413  $isTitle = strtolower($this->structAttr->istitle);
414  if ($isTitle) {
415  if (!in_array($isTitle, $this->yesno)) {
416  $this->addError(ErrorCode::getError('ATTR0400', $isTitle, $this->attrid));
417  } elseif ($isTitle == 'y' && (!$this->isNodeHasValue())) {
418  $this->addError(ErrorCode::getError('ATTR0401', $this->attrid));
419  }
420  }
421  }
422 
423  private function checkIsNeeded()
424  {
425  $isNeeded = strtolower($this->structAttr->isneeded);
426  if ($isNeeded) {
427  if (!in_array($isNeeded, $this->yesno)) {
428  $this->addError(ErrorCode::getError('ATTR0900', $isNeeded, $this->attrid));
429  } elseif ($isNeeded == 'y' && (!$this->isNodeHasValue())) {
430  $this->addError(ErrorCode::getError('ATTR0901', $this->attrid));
431  }
432  }
433  }
434  /**
435  * @return bool return false if some error detected
436  */
437  private function checkPhpFile()
438  {
439  $goodFile = true;
440  $phpFile = trim($this->structAttr->phpfile);
441  if ($phpFile && $phpFile != '-' && ($this->getType() != "action")) {
442  $phpFile = sprintf("EXTERNALS/%s", $phpFile);
443  if (!file_exists($phpFile)) {
444  $this->addError(ErrorCode::getError('ATTR1100', $phpFile, $this->attrid));
445  $goodFile = false;
446  } else {
447  $realPhpFile = realpath($phpFile);
448  if (CheckClass::phpLintFile($realPhpFile, $output) === false) {
449  $this->addError(ErrorCode::getError('ATTR1101', $phpFile, $this->attrid, implode("\n", $output)));
450  $goodFile = false;
451  } else {
452  require_once $phpFile;
453  }
454  }
455  }
456  return $goodFile;
457  }
458 
459  private function checkPhpFunctionOrMethod()
460  {
461  $phpFunc = trim($this->structAttr->phpfunc);
462  $phpFile = trim($this->structAttr->phpfile);
463  $type = $this->getType();
464  if ($phpFunc && $phpFunc != '-' && ($type != "action") && ($type != "enum")) {
465  if ($phpFile && $phpFile != '-') {
466  // parse function for input help
467  $this->checkPhpFunction();
468  } else {
469  // parse method for computed attribute
470  $this->checkPhpMethod();
471  }
472  }
473  }
474 
475  private function checkEnum()
476  {
477  $phpFunc = $this->structAttr->phpfunc;
478  $phpFile = trim($this->structAttr->phpfile);
479  $type = $this->getType();
480  if ((!$phpFile || $phpFile == '-') && $phpFunc && ($type == "enum")) {
481  // parse static enum
482  $enums = str_replace(array(
483  "\\.",
484  "\\,"
485  ) , '-', $phpFunc); // to replace dot & comma separators
486  $topt = explode(",", $enums);
487  foreach ($topt as $opt) {
488  if (strpos($opt, '|') === false) {
489  $enumKey = $opt;
490  $enumLabel = null;
491  } else list($enumKey, $enumLabel) = explode("|", $opt, 2);
492  if ($enumKey === '') {
493  $this->addError(ErrorCode::getError('ATTR1272', $opt, $this->attrid));
494  } elseif (!preg_match('/^[\x20-\x7E]+$/', $enumKey)) {
495  $this->addError(ErrorCode::getError('ATTR1271', $opt, $this->attrid));
496  } else if ($enumLabel === null) {
497  $this->addError(ErrorCode::getError('ATTR1270', $opt, $this->attrid));
498  }
499  }
500  }
501  }
502 
503  private function checkPhpFunction()
504  {
505  $phpFunc = trim($this->structAttr->phpfunc);
506  $phpFile = trim($this->structAttr->phpfile);
507  $type = $this->getType();
508  if ($phpFunc && $phpFunc != '-' && ($type != "action")) {
509  if ($phpFile && $phpFile != '-') {
510  // parse function for input help
511  $oParse = new parseFamilyFunction();
512  $strucFunc = $oParse->parse($phpFunc, ($type == 'enum'));
513  if ($strucFunc->getError()) {
514  $this->addError(ErrorCode::getError('ATTR1200', $this->attrid, $strucFunc->getError()));
515  } else {
516  $phpFuncName = $strucFunc->functionName;
517  try {
518  $refFunc = new ReflectionFunction($phpFuncName);
519  if ($refFunc->isInternal()) {
520  $this->addError(ErrorCode::getError('ATTR1209', $phpFuncName));
521  } else {
522 
523  $targetFile = $refFunc->getFileName();
524  $realPhpFile = realpath(sprintf("EXTERNALS/%s", $phpFile));
525  if ($targetFile != $realPhpFile) {
526  if (!$oParse->appName) {
527  $this->addError(ErrorCode::getError('ATTR1210', $phpFuncName, $realPhpFile));
528  }
529  } else {
530  $numArgs = $refFunc->getNumberOfRequiredParameters();
531  if ($numArgs > count($strucFunc->inputs)) {
532  $this->addError(ErrorCode::getError('ATTR1211', $phpFuncName, $numArgs));
533  }
534  }
535  }
536  }
537  catch(Exception $e) {
538  $this->addError(ErrorCode::getError('ATTR1203', $phpFuncName));
539  }
540  }
541  } else {
542  // parse method for computed attribute
543 
544  }
545  }
546  }
547 
548  private function checkPhpMethod()
549  {
550  $phpFunc = trim($this->structAttr->phpfunc);
551  $type = $this->getType();
552 
553  if ($this->isModAttr && (!$type)) return; // cannot really test if has not type
554  $oParse = new parseFamilyMethod();
555  $strucFunc = $oParse->parse($phpFunc, ($type == 'enum'));
556  if ($strucFunc->getError()) {
557  $this->addError(ErrorCode::getError('ATTR1250', $this->attrid, $strucFunc->getError()));
558  } else {
559  // validity of method call cannot be tested here
560  // it is tested in checkEnd
561  if ($this->lineType == 'PARAM' && isset($strucFunc->outputs) && count($strucFunc->outputs) > 0) {
562  $this->addError(ErrorCode::getError('ATTR0211', $this->attrid));
563  }
564  }
565  }
566 
567  private function checkPhpConstraint()
568  {
569  $constraint = trim($this->structAttr->constraint);
570  if ($constraint) {
571  if ($this->isModAttr && $constraint == '-') {
572  return;
573  }
574  $oParse = new parseFamilyMethod();
575  $strucFunc = $oParse->parse($constraint, true);
576  if ($strucFunc->getError()) {
577  $this->addError(ErrorCode::getError('ATTR1400', $this->attrid, $strucFunc->getError()));
578  } else {
579  // validity of method call cannot be tested here
580  // it is tested in checkEnd
581 
582  }
583  }
584  }
585 
586  private function checkOptions()
587  {
588 
589  $options = trim($this->structAttr->options);
590  if ($options) {
591  $topt = explode("|", $options);
592  foreach ($topt as $opt) {
593  if (strpos($opt, '=') === false) {
594  $optName = $opt;
595  $optValue = null;
596  } else list($optName, $optValue) = explode("=", $opt, 2);
597  if (!preg_match('/^[a-z_-]{1,63}$/', $optName)) {
598  $this->addError(ErrorCode::getError('ATTR1500', $optName, $this->attrid));
599  } else if ($optValue === null) {
600  $this->addError(ErrorCode::getError('ATTR1501', $optName, $this->attrid));
601  }
602  }
603  }
604  }
605  /**
606  * @param string $attrid
607  * @return bool
608  */
609  public static function checkAttrSyntax($attrid)
610  {
611  if (preg_match("/^[A-Z_0-9]{1,63}$/i", $attrid)) {
612  return true;
613  }
614  return false;
615  }
616 
617  private function getType($type = null)
618  {
619  if ($type === null) {
620  $type = trim($this->structAttr->type);
621  }
622  $rtype = '';
623  if (preg_match('/^([a-z]+)\(["\'].+["\']\)$/i', $type, $reg)) {
624  $rtype = $reg[1];
625  } elseif (preg_match('/^([a-z]+)$/i', $type, $reg)) {
626  $rtype = $reg[1];
627  }
628  return $rtype;
629  }
630 
631  private function getFormat()
632  {
633  $type = trim($this->structAttr->type);
634  $rformat = '';
635 
636  if (preg_match('/^([a-z]+)\(["\'](.+)["\']\)$/i', $type, $reg)) {
637  $rformat = $reg[2];
638  }
639  return $rformat;
640  }
641 
642  private function isNodeNeedSet()
643  {
644  if ($this->isModAttr) return false;
645  $type = $this->getType();
646  return (($type != "tab") && ($type != "frame") && ($type != "menu") && ($type != "action"));
647  }
648 
649  private function isNodeNeedOrder()
650  {
651  if ($this->isModAttr) return false;
652  $type = $this->getType();
653  return (($type != "tab") && ($type != "frame"));
654  }
655 
656  private function isNodeHasValue()
657  {
658  $type = $this->getType();
659  return (!in_array($type, $this->noValueTypes));
660  }
661 }
664 {
665  public $id;
666  public $setid;
667  public $label;
668  public $istitle;
669  public $isabstract;
670  public $type;
671  public $order;
672  public $visibility;
673  public $isneeded;
674  public $link;
675  public $phpfile;
676  public $phpfunc;
677  public $elink;
678  public $constraint;
679  public $options;
680  private $dataOrder = array(
681  "id",
682  "setid",
683  "label",
684  "istitle",
685  "isabstract",
686  "type",
687  "order",
688  "visibility",
689  "isneeded",
690  "link",
691  "phpfile",
692  "phpfunc",
693  "elink",
694  "constraint",
695  "options"
696  );
697 
698  public function __construct(array $data = array())
699  {
700  if (count($data) > 0) $this->set($data);
701  }
702 
703  public function set(array $data)
704  {
705  $cid = 1;
706  foreach ($this->dataOrder as $key) {
707  if ($key == 'phpfunc') $this->$key = isset($data[$cid]) ? $data[$cid] : '';
708  else $this->$key = isset($data[$cid]) ? trim($data[$cid]) : '';
709  $cid++;
710  }
711  }
712 }
print< H1 > Check Database< i > $dbaccess</i ></H1 > $a
Definition: checklist.php:45
set(array $data)
Definition: checkAttr.php:695
check(array $data, &$extra=null)
Definition: checkAttr.php:170
static getError($code, $args=null)
Definition: ErrorCode.php:27
print docid
Definition: migrEnum.php:33
$docid
Definition: cleanFamily.php:13
Check application accesses when importing definition.
Definition: checkAttr.php:12
static phpLintFile($fileName, &$output)
Definition: CheckClass.php:86
static checkAttrSyntax($attrid)
Definition: checkAttr.php:609
addError($msg)
Definition: CheckData.php:29
__construct(array $data=array())
Definition: checkAttr.php:690
simpleQuery($dbaccess, $query, &$result=array(), $singlecolumn=false, $singleresult=false, $useStrict=null)
Definition: Lib.Common.php:484
$data
← centre documentaire © anakeen