Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.CheckDb.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 /**
7  * Verify several point for the integrity of the system
8  *
9  * @author Anakeen
10  * @version $Id: checklist.php,v 1.8 2008/12/31 14:37:26 jerome Exp $
11  * @package FDL
12  * @subpackage CORE
13  */
14 /**
15  */
16 
17 class checkDb
18 {
19  /*
20  * @var resource $r
21  */
22  private $r;
23  private $connect;
24  /**
25  * @var array;
26  */
27  private $tparam;
28  /**
29  * @var array
30  */
31  private $tout;
32 
33  const OK = "green";
34  const KO = "red";
35  const BOF = "orange";
36 
37  public function __construct($connect)
38  {
39  $r = @pg_connect($connect);
40  $this->connect = $connect;
41 
42  if ($r) $this->r = $r;
43  }
44 
45  public function checkConnection()
46  {
47  $this->tout["main connection db"] = array(
48  "status" => $this->r ? self::OK : self::KO,
49  "msg" => $this->connect
50  );
51  return ($this->r != null);
52  }
53 
54  public function checkUnreferenceUsers()
55  {
56  $result = pg_query($this->r, "SELECT * from groups where iduser not in (select id from users);");
57  $pout = array();
58  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
59  $pout[$row["iduser"]][] = $row["idgroup"];
60  }
61  if (count($pout) > 0) $msg = sprintf("%d unreferenced users<pre>%s</pre>", count($pout) , print_r($pout, true));
62  else $msg = "";
63  $this->tout["unreferenced user in group"] = array(
64  "status" => (count($pout) == 0) ? self::OK : self::BOF,
65  "msg" => $msg
66  );
67  }
68 
69  public function checkDateStyle()
70  {
71  $ret = array(
72  'status' => self::OK,
73  'msg' => ''
74  );
75  simpleQuery('', "SELECT current_database()", $dbname, true, true, true);
76  simpleQuery('', "SHOW DateStyle", $dateStyle, true, true, true);
77  if ($dateStyle !== 'ISO, DMY') {
78  $ret['status'] = self::KO;
79  $ret['msg'] = sprintf("Database's \"DateStyle\" should be set to 'ISO, DMY' (actual value is '%s')&nbsp;<br/><pre>ALTER DATABASE %s SET DateStyle = 'ISO, DMY';</pre>", htmlspecialchars($dateStyle, ENT_QUOTES) , htmlspecialchars(pg_escape_identifier($dbname)));
80  }
81  $this->tout["dateStyle"] = $ret;
82  }
83 
85  {
86  $res = array(
87  "status" => self::OK,
88  "msg" => ""
89  );
90  simpleQuery('', "SELECT current_database()", $dbname, true, true, true);
91  simpleQuery('', "SHOW standard_conforming_strings", $value, true, true, true);
92  if ($value !== 'off') {
93  $res['status'] = self::KO;
94  $res['msg'] = sprintf("Database's \"standard_conforming_strings\" should be set to 'off' (actual value is '%s')&nbsp;:<br/><pre>ALTER DATABASE %s SET standard_conforming_strings = off;</pre>", htmlspecialchars($value, ENT_QUOTES) , htmlspecialchars(pg_escape_identifier($dbname)));
95  }
96  $this->tout["standard_conforming_strings"] = $res;
97  }
98 
99  public function checkUserAsGroup()
100  {
101  $result = pg_query($this->r, "SELECT distinct(idgroup) from groups where idgroup not in (select id from users where accounttype!='U');");
102  $pout = array();
103  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
104  $pout[] = $row["idgroup"];
105  }
106  if (count($pout) > 0) $msg = sprintf("%d users detected as group<br><kbd>%s</kbd>", count($pout) , implode(", ", $pout));
107  else $msg = "";
108  $this->tout["user as group"] = array(
109  "status" => (count($pout) == 0) ? self::OK : self::KO,
110  "msg" => $msg
111  );
112  }
113 
114  public function checkUnreferencedAction()
115  {
116  $result = pg_query($this->r, "SELECT * from action where id_application not in (select id from application);");
117  $pout = array();
118  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
119  $pout[] = $row["name"];
120  }
121  if (count($pout) > 0) $msg = sprintf("%d unreferenced actions<br><kbd>%s</kbd>", count($pout) , implode(", ", $pout));
122  else $msg = "";
123  $this->tout["unreferenced actions"] = array(
124  "status" => (count($pout) == 0) ? self::OK : self::BOF,
125  "msg" => $msg
126  );
127  }
128 
129  public function checkUnreferencedParameters()
130  {
131  $result = pg_query($this->r, "SELECT * from paramdef where appid not in (select id from application);");
132  $pout = array();
133  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
134  $pout[] = $row["name"];
135  }
136  $result = pg_query($this->r, "SELECT * from paramv where appid not in (select id from application);");
137  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
138  $pout[] = $row["name"];
139  }
140  if (count($pout) > 0) $msg = sprintf("%d unreferenced parameters<br><kbd>%s</kbd>", count($pout) , implode(", ", $pout));
141  else $msg = "";
142  $this->tout["unreferenced parameters"] = array(
143  "status" => (count($pout) == 0) ? self::OK : self::BOF,
144  "msg" => $msg
145  );
146  }
147 
148  public function checkUnreferencedAcl()
149  {
150  $result = pg_query($this->r, "SELECT * from acl where id_application not in (select id from application);");
151  $pout = array();
152  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
153  $pout[] = $row["name"];
154  }
155  if (count($pout) > 0) $msg = sprintf("%d unreferenced acl<br><kbd>%s</kbd>", count($pout) , implode(", ", $pout));
156  else $msg = "";
157  $this->tout["unreferenced acl"] = array(
158  "status" => (count($pout) == 0) ? self::OK : self::BOF,
159  "msg" => $msg
160  );
161  }
162 
163  public function getUnreferencedPermission()
164  {
165  $result = pg_query($this->r, "SELECT * from permission where id_acl not in (select id from acl);");
166  $nb = pg_num_rows($result);
167  $result = pg_query($this->r, "SELECT * from permission where id_user not in (select id from users);");
168  $nb+= pg_num_rows($result);
169  $result = pg_query($this->r, "SELECT * from permission where id_application not in (select id from application);");
170  $nb+= pg_num_rows($result);
171  $msg = '';
172  if ($nb > 0) $msg = sprintf("%d unreferenced permissions", ($nb));
173  $this->tout["unreferenced permission"] = array(
174  "status" => ($nb == 0) ? self::OK : self::BOF,
175  "msg" => $msg
176  );
177  }
178 
179  public function checkDoubleFrom()
180  {
181  $result = pg_query($this->r, "SELECT * from (SELECT id, count(id) as c from doc group by id) as Z where Z.c > 1;");
182  $pout = array();
183  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
184  $pout[$row["id"]] = $row["c"];
185  }
186  if (count($pout) > 0) $msg = sprintf("%d double id detected<pre>%s</pre>", count($pout) , print_r($pout, true));
187  else $msg = "";
188  $this->tout["double doc id"] = array(
189  "status" => (count($pout) == 0) ? self::OK : self::KO,
190  "msg" => $msg
191  );
192  }
193  public function checkDoubleName()
194  {
195  $result = pg_query($this->r, "select * from (select name, count(name) as c from doc where name is not null and name != '' and locked != -1 group by name) as Z where Z.c >1");
196  $pout = array();
197  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
198  $pout[$row["name"]] = $row["c"];
199  }
200  if (count($pout) > 0) $msg = sprintf("%d double detected<pre>%s</pre>", count($pout) , print_r($pout, true));
201  else $msg = "";
202  $this->tout["double doc name"] = array(
203  "status" => (count($pout) == 0) ? self::OK : self::KO,
204  "msg" => $msg
205  );
206  }
207 
208  public function checkMultipleAlive()
209  {
210  $result = pg_query($this->r, "select id, title from docread where id in (SELECT m AS id FROM (SELECT min(id) AS m, initid, count(initid) AS c FROM docread WHERE locked != -1 AND doctype != 'T' GROUP BY docread.initid) AS z where z.c > 1);");
211  $pout = array();
212  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
213  $pout[$row["id"]] = $row["title"];
214  }
215  if (count($pout) > 0) $msg = sprintf("%d multiple alive<pre>%s</pre>", count($pout) , print_r($pout, true));
216  else $msg = "";
217  $this->tout["multiple alive"] = array(
218  "status" => (count($pout) == 0) ? self::OK : self::KO,
219  "msg" => $msg
220  );
221  }
222 
223  public function checkInheritance()
224  {
225  $result = pg_query($this->r, "select * from docfam");
226  $pout = array();
227  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
228  $fromid = intval($row["fromid"]);
229  if ($fromid == 0) $fromid = "";
230  $fid = intval($row["id"]);
231  $test = pg_query($this->r, sprintf("SELECT relname from pg_class where oid in (SELECT inhparent from pg_inherits where inhrelid =(SELECT oid FROM pg_class where relname='doc%d'));", $fid));
232  $dbfrom = pg_fetch_array($test, NULL, PGSQL_ASSOC);
233  if ($dbfrom["relname"] != "doc$fromid") {
234  $pout[] = sprintf("Family %s [%d]: fromid = %d, pg inherit=%s", $row["name"], $row["id"], $row["fromid"], $dbfrom["relname"]);
235  }
236  }
237  $this->tout["family inheritance"] = array(
238  "status" => (count($pout) == 0) ? self::OK : self::KO,
239  "msg" => implode("<br/>", $pout)
240  );
241  }
242 
243  public function checkNetworkUser()
244  {
245  // Test User LDAP (NetworkUser Module)
246  $appNameList = array();
247  $result = pg_query($this->r, "SELECT name FROM application;");
248  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
249  $appNameList[] = $row['name'];
250  }
251  $nuAppExists = (array_search('NU', $appNameList) === false) ? false : true;
252  $ldaphost = $this->getGlobalParam("NU_LDAP_HOST");
253  $ldapport = $this->getGlobalParam("NU_LDAP_PORT");
254  $ldapmode = $this->getGlobalParam("NU_LDAP_MODE");
255  if ($nuAppExists && $ldaphost) {
256  include_once ('../../../NU/Lib.NU.php');
257 
258  $ldapBindDn = $this->getGlobalParam('NU_LDAP_BINDDN');
259  $ldapPassword = $this->getGlobalParam('NU_LDAP_PASSWORD');
260 
261  $baseList = array();
262  array_push($baseList, array(
263  'dn' => $this->getGlobalParam('NU_LDAP_USER_BASE_DN') ,
264  'filter' => $this->getGlobalParam('NU_LDAP_USER_FILTER')
265  ));
266  array_push($baseList, array(
267  'dn' => $this->getGlobalParam('NU_LDAP_GROUP_BASE_DN') ,
268  'filter' => $this->getGlobalParam('NU_LDAP_GROUP_FILTER')
269  ));
270 
271  foreach ($baseList as $base) {
272  $testName = sprintf("connection to '%s'", $base['dn']);
273  $this->tout[$testName] = array();
274  /** @noinspection PhpUndefinedFunctionInspection */
275  $uri = getLDAPUri($ldapmode, $ldaphost, $ldapport);
276  $conn = ldap_connect($uri);
277  if ($conn === false) {
278  $this->tout[$testName]['status'] = self::KO;
279  $this->tout[$testName]['msg'] = sprintf("Could not connect to LDAP server '%s': %s", $uri, $php_errormsg);
280  continue;
281  }
282 
283  ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
284  ldap_set_option($conn, LDAP_OPT_REFERRALS, 0);
285 
286  if ($ldapmode == 'tls') {
287  $ret = ldap_start_tls($conn);
288  if ($ret === false) {
289  $this->tout[$testName]['status'] = self::KO;
290  $this->tout[$testName]['msg'] = sprintf("Could not negotiate TLS with server '%s': %s", $uri, ldap_error($conn));
291  continue;
292  }
293  }
294 
295  $bind = ldap_bind($conn, $ldapBindDn, $ldapPassword);
296  if ($bind === false) {
297  $this->tout[$testName]['status'] = self::KO;
298  $this->tout[$testName]['msg'] = sprintf("Could not bind with bind DN '%s' on server '%s': %s", $ldapBindDn, $uri, ldap_error($conn));
299  ldap_close($conn);
300  continue;
301  }
302 
303  $res = ldap_search($conn, $base['dn'], sprintf("(&(objectClass=*)%s)", $base['filter']));
304  if ($res === false) {
305  $this->tout[$testName]['status'] = self::KO;
306  $this->tout[$testName]['msg'] = sprintf("LDAP search on base '%s' with filter '%s' failed: %s", $base['dn'], $base['filter'], ldap_error($conn));
307  ldap_close($conn);
308  continue;
309  }
310 
311  $count = ldap_count_entries($conn, $res);
312  if ($count === false) {
313  $this->tout[$testName]['status'] = self::KO;
314  $this->tout[$testName]['msg'] = sprintf("Error counting result entries: %s", ldap_error($conn));
315  ldap_close($conn);
316  continue;
317  }
318  if ($count <= 0) {
319  $this->tout[$testName]['status'] = self::BOF;
320  $this->tout[$testName]['msg'] = sprintf("Search returned 0 entries...");
321  ldap_close($conn);
322  continue;
323  }
324 
325  $this->tout[$testName]['status'] = self::OK;
326  $this->tout[$testName]['msg'] = sprintf("Search returned %s entries.", $count);
327  ldap_close($conn);
328  }
329  }
330  }
331 
332  public function checkcleanContext()
333  {
334  $testName = "cleanContext cron job execution";
335  $sql = "SELECT min(cdate) AS mincdate, count(id) AS count FROM doc WHERE doctype = 'T' AND cdate < now() - INTERVAL '24h'";
336  try {
337  simpleQuery('', $sql, $res, false, false, true);
338 
339  if ($res[0]['count'] > 0) {
340  $err = sprintf("<p>Oldest temporary document is &gt; 24 hours: <code>%s</code></p>", htmlspecialchars($res[0]['mincdate']));
341  $err.= "<p>Dynacase crontab might not be active or correctly registered.</p>";
342  $err.= "<ul>";
343  $err.= "<li>Check that the Dynacase crontab 'FREEDOM/freedom.cron' is correctly registered in the Apache's user crontab: <pre>./wsh.php --api=manageContextCrontab --cmd=list</pre></li>";
344  $err.= "<li>If the crontab is not registered, try to register it: <pre>./wsh.php --api=manageContextCrontab --cmd=register --file=FREEDOM/freedom.cron</pre>";
345  $err.= "<li>If the crontab is correctly registered but not executed, check that the system's cron daemon is correctly running.</li>";
346  $err.= "</ul>";
347  throw new Exception($err);
348  }
349  }
350  catch(Exception $e) {
351  $this->tout[$testName] = array(
352  'status' => self::KO,
353  'msg' => $e->getMessage()
354  );
355  return;
356  }
357  $this->tout[$testName] = array(
358  'status' => self::OK,
359  'msg' => ''
360  );
361  return;
362  }
363  /**
364  * @param NormalAttribute $oa
365  * @param string $pgtype
366  * @param string $rtype
367  * @return string
368  */
369  private static function verifyDbAttr(&$oa, $pgtype, &$rtype)
370  {
371  $err = '';
372  $rtype = 'text';
373  if (!$oa->inArray()) {
374  switch ($oa->type) {
375  case 'int':
376  case 'integer':
377  $rtype = 'int4';
378  break;
379 
380  case 'money':
381  case 'double':
382  case 'float':
383  $rtype = 'float8';
384  break;
385 
386  case 'date':
387  $rtype = 'date';
388  break;
389 
390  case 'timestamp':
391  $rtype = 'timestamp';
392  break;
393 
394  case 'time':
395  $rtype = 'time';
396  break;
397  }
398  }
399 
400  if ($rtype != $pgtype) {
401  $err = sprintf("expected [%s], found [%s]", $rtype, $pgtype);
402  }
403  return $err;
404  }
405  /**
406  * detected sql type inconsistence with declaration
407  * @param $famid
408  * @param NormalAttribute $aoa if wan't test only one attribute
409  * @throws Dcp\Exception
410  * @return array empty array if no error, else an item string by error detected
411  */
412  public static function verifyDbFamily($famid, NormalAttribute $aoa = null)
413  {
414  $cr = array();
415 
416  $fam = new_doc('', $famid);
417  if ($fam->isAlive()) {
418  $sql = sprintf("select pg_attribute.attname,pg_type.typname FROM pg_attribute, pg_type where pg_type.oid=pg_attribute.atttypid and pg_attribute.attrelid=(SELECT oid from pg_class where relname='doc%d') order by pg_attribute.attname;", $fam->id);
419  simpleQuery('', $sql, $res);
420  $pgtype = array();
421  foreach ($res as $pgattr) {
422  if ($pgattr["typname"] == "timestamptz") $pgattr["typname"] = "timestamp";
423  $pgtype[$pgattr["attname"]] = $pgattr["typname"];
424  }
425 
426  if (!$aoa) {
427  $oas = $fam->getNormalAttributes();
428  } else {
429  $oas = array(
430  $aoa
431  );
432  }
433  foreach ($oas as $oa) {
434  $aid = $oa->id;
435  if (($oa->docid == $fam->id) && ($oa->type != "array") && ($oa->type != "frame") && ($oa->type != "tab") && ($oa->type != "") && ($oa->type != "menu")) {
436  $err = self::verifyDbAttr($oa, $pgtype[$aid], $rtype);
437  if ($err) {
438  $cr[] = sprintf("family %s, %s (%s) : %s\n", $fam->getTitle() , $aid, $oa->type, $err) . sprintf("\ttry : drop view family.%s; \n", strtolower($fam->name)) . sprintf("\tand : alter table doc%d alter column %s type %s using %s::%s; \n", $fam->id, $aid, $rtype, $aid, $rtype);
439  }
440  }
441  }
442  } else {
443  throw new Dcp\Exception("no family $famid");
444  }
445  return $cr;
446  }
447 
448  public static function getOrphanAttributes($famid)
449  {
450 
451  $d = new Doc();
452  $fam = new_doc('', $famid);
453  $sql = sprintf("select column_name from information_schema.columns where table_name = 'doc%d'", $fam->id);
454  simpleQuery('', $sql, $res, true);
455 
456  $nAttributes = $fam->getNormalAttributes();
457  $oasIds = array_keys($nAttributes);
458  $oasIds = array_merge($oasIds, $d->fields, $d->sup_fields, array(
459  "fulltext",
460  "svalues"
461  ));
462 
463  foreach ($nAttributes as $attrid => $oa) {
464  if ($oa->type == "file") {
465  $oasIds[] = $attrid . '_txt';
466  $oasIds[] = $attrid . '_vec';
467  }
468  }
469 
470  $orphan = array();
471  foreach ($res as $dbAttr) {
472  if (!in_array($dbAttr, $oasIds)) {
473  if ($dbAttr != "forumid") {
474  $orphan[] = $dbAttr;
475  }
476  }
477  }
478  return $orphan;
479  }
480  /**
481  * verify attribute sql type
482  * @return void
483  */
484  public function checkAttributeType()
485  {
486  $testName = 'attribute type';
487  include_once ("../../../FDL/Class.Doc.php");
488  $err = simpleQuery('', "select id from docfam", $families, true);
489 
490  foreach ($families as $famid) {
491  $cr = $this->verifyDbFamily($famid);
492  if (count($cr) > 0) {
493  $err.= implode("<br/>", $cr);
494  }
495  }
496 
497  $this->tout[$testName]['status'] = ($err) ? self::KO : self::OK;
498  $this->tout[$testName]['msg'] = '<pre>' . $err . '</pre>';
499  }
500  /**
501  * verify attribute sql type
502  * @return void
503  */
504  public function checkAttributeOrphan()
505  {
506  $testName = 'attribute orphan';
507  include_once ("../../../FDL/Class.Doc.php");
508  if (($err = $this->computeDropColumns($treeNode)) != '') {
509  $this->tout[$testName]['status'] = self::BOF;
510  $this->tout[$testName]['msg'] = sprintf("<pre>%s</pre>", htmlspecialchars($err, ENT_QUOTES));
511  }
512 
513  $this->getSQLDropColumns($treeNode, $cmds);
514 
515  $html = '';
516  if (count($cmds) > 0) {
517  $html.= "BEGIN;<br/>";
518  $html.= "<br/>";
519  $html.= implode("<br/>", array_map(function ($v)
520  {
521  return htmlspecialchars($v, ENT_QUOTES);
522  }
523  , $cmds)) . "<br/>";
524  $html.= "<br/>";
525  $html.= "COMMIT;";
526  }
527 
528  $this->tout[$testName]['status'] = ($html !== '') ? self::BOF : self::OK;
529  $this->tout[$testName]['msg'] = '<pre>' . $html . '</pre>';
530 
531  return;
532  }
533  /**
534  * Recursively walk up the tree node to find if a specific column has
535  * already been marked for deletion in a parent family.
536  *
537  * @param array $node The tree node starting point
538  * @param string $column The column's name to lookup for
539  * @return bool bool(true) if the column is already marked for deletion
540  * in a parent family or bool(false) if not
541  */
542  static function isDroppedInNode(&$node, $column)
543  {
544  if (isset($node['drop'][$column])) {
545  return true;
546  }
547  if (isset($node['parent'])) {
548  return self::isDroppedInNode($node['parent'], $column);
549  }
550  return false;
551  }
552  /**
553  * Compute the required SQL commands to drop the columns marked for
554  * deletion in the given family tree.
555  *
556  * @param array $node The family tree obtained with ::computeDropColumns()
557  * @param array $cmds Resulting SQL commands
558  * @param bool $combined bool(true) to combine multiple DROP instructions
559  * into a single ALTER TABLE instruction,
560  * bool(false) to generate multiple ALTER TABLE
561  * instructions containing each a single DROP
562  * instruction.
563  */
564  public function getSQLDropColumns(&$node, &$cmds = array() , $combined = true)
565  {
566  if (isset($node['drop']) && is_array($node['drop'])) {
567  if (count($node['drop']) > 0) {
568  $cmds[] = sprintf("-- Family '%s', table doc%d", $node['name'], $node['id']);
569  $alter = sprintf("ALTER TABLE doc%d", $node['id']);
570  $drops = array();
571  foreach ($node['drop'] as $column) {
572  $drops[] = sprintf("DROP COLUMN IF EXISTS %s CASCADE", pg_escape_identifier($column));
573  }
574  if ($combined) {
575  $alter.= "\n\t" . join(",\n\t", $drops) . ";";
576  $cmds[] = $alter;
577  } else {
578  foreach ($drops as $drop) {
579  $cmds[] = $alter . " " . $drop . ";";
580  }
581  }
582  $cmds[] = 'SELECT refreshFamilySchemaViews();';
583  $cmds[] = "";
584  }
585  }
586  if (isset($node['childs'])) {
587  foreach ($node['childs'] as & $child) {
588  $this->getSQLDropColumns($child, $cmds, $combined);
589  }
590  }
591  }
592  /**
593  * Compute a tree of families with columns to drop
594  *
595  * @param array $node The families tree returned with columns to drop
596  * @param int $fromId Family id to start from (default is 0)
597  * @return string empty string on success, non-empty string containing the error message on failure
598  * @throws \Dcp\Db\Exception
599  */
600  public function computeDropColumns(&$node = null, $fromId = 0)
601  {
602  /*
603  * List of families ordered by parenthood:
604  * parents on top, childs at bottom
605  */
606  $sql = <<<'EOF'
607 WITH RECURSIVE topfam(id, fromid) AS (
608  SELECT id, fromid FROM docfam WHERE fromid = %d
609  UNION
610  SELECT docfam.id, docfam.fromid FROM topfam, docfam WHERE docfam.fromid = topfam.id
611 )
612 SELECT * FROM topfam;
613 EOF;
614  $sql = sprintf($sql, $fromId);
615  if (($err = simpleQuery('', $sql, $families, false, false, null)) != '') {
616  return $err;
617  }
618 
619  if ($node === null) {
620  $node = array(
621  'name' => '',
622  'id' => $fromId,
623  'childs' => array()
624  );
625  }
626  foreach ($families as $fam) {
627  $doc = new_Doc('', $fam['id']);
628  if (!is_object($doc) || !$doc->isAlive()) {
629  continue;
630  }
631  if ($fam['fromid'] != $fromId) {
632  continue;
633  }
634  $drop = array();
635  $orphans = self::getOrphanAttributes($fam['id']);
636  foreach ($orphans as $column) {
637  if (!self::isDroppedInNode($node, $column)) {
638  $drop[$column] = $column;
639  }
640  }
641  $node['childs'][$fam['id']] = array(
642  'name' => $doc->name,
643  'id' => $fam['id'],
644  'fromid' => $fam['fromid'],
645  'drop' => $drop,
646  'parent' => & $node,
647  'childs' => array()
648  );
649  }
650  foreach ($node['childs'] as & $child) {
651  if (($err = $this->computeDropColumns($child, $child['id'])) != '') {
652  return $err;
653  }
654  }
655  return '';
656  }
657  /**
658  * Do all analyses
659  *
660  * @return array
661  */
662  public function getFullAnalyse()
663  {
664  if ($this->checkConnection()) {
665  $this->checkDateStyle();
667  $this->checkUnreferenceUsers();
668  $this->checkUserAsGroup();
669  $this->checkUnreferencedAction();
671  $this->checkUnreferencedAcl();
672  $this->getUnreferencedPermission();
673  $this->checkDoubleFrom();
674  $this->checkDoubleName();
675  $this->checkInheritance();
676  $this->checkMultipleAlive();
677  $this->checkNetworkUser();
678  $this->checkAttributeType();
679  $this->checkAttributeOrphan();
680  $this->checkcleanContext();
683  $this->checkUnnamedFamilies();
684  }
685  return $this->tout;
686  }
687 
688  private function initGlobalParam()
689  {
690  $result = pg_query($this->r, "SELECT * FROM paramv where type='G'");
691  if (!$result) {
692  }
693  $this->tparam = array();
694  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
695  $this->tparam[$row["name"]] = $row["val"];
696  }
697  }
698  private function getGlobalParam($key)
699  {
700  if (!$this->tparam) {
701  $this->initGlobalParam();
702  }
703  return isset($this->tparam[$key]) ? $this->tparam[$key] : null;
704  }
705  public function checkUnnamedFamilies()
706  {
707  $sql = <<<'EOSQL'
708 SELECT docfam.id AS id, docfam.name AS docfam_name, docname.name AS docname_name, docread.name AS docread_name
709 FROM docfam
710  LEFT JOIN docname ON docfam.id = docname.id
711  LEFT JOIN docread ON docfam.id = docread.id
712 WHERE
713  docfam.name IS NULL OR
714  docname.name IS NULL OR
715  docread.name IS NULL
716 ORDER BY docfam.id ASC
717 EOSQL;
718  $result = pg_query($this->r, $sql);
719  $unnamedDocfam = array();
720  $unnamedDocname = array();
721  $unnamedDocread = array();
722  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
723  if ($row['docfam_name'] == '') {
724  $unnamedDocfam[] = $row['id'];
725  }
726  if ($row['docname_name'] == '') {
727  $unnamedDocname[] = $row['id'];
728  }
729  if ($row['docread_name'] == '') {
730  $unnamedDocread[] = $row['id'];
731  }
732  }
733  $unnamedDocfamCount = count($unnamedDocfam);
734  $unnamedDocreadCount = count($unnamedDocread);
735  $unnamedDocnameCount = count($unnamedDocname);
736  $pout = array();
737  if ($unnamedDocfamCount > 0) {
738  $pout[] = sprintf("%s unnamed famil%s in docfam: <pre>{%s}</pre>", $unnamedDocfamCount, ($unnamedDocfamCount > 1 ? 'ies' : 'y') , join(', ', $unnamedDocfam));
739  }
740  if ($unnamedDocreadCount > 0) {
741  $pout[] = sprintf("%s unnamed famil%s in docfam: <pre>{%s}</pre>", $unnamedDocreadCount, ($unnamedDocreadCount > 1 ? 'ies' : 'y') , join(', ', $unnamedDocread));
742  }
743  if ($unnamedDocnameCount > 0) {
744  $pout[] = sprintf("%s unnamed famil%s in docfam: <pre>{%s}</pre>", $unnamedDocnameCount, ($unnamedDocnameCount > 1 ? 'ies' : 'y') , join(', ', $unnamedDocname));
745  }
746  $this->tout["missing family name"] = array(
747  "status" => (count($pout) <= 0) ? self::OK : self::BOF,
748  "msg" => (count($pout) <= 0) ? '' : '<ul><li>' . join('</li><li>', $pout) . '</li></ul>'
749  );
750  }
752  {
753  $result = pg_query($this->r, "SELECT id FROM doc WHERE id < 1e9 AND NOT EXISTS (SELECT 1 FROM docread WHERE docread.id = doc.id)");
754  $pout = array();
755  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
756  $pout[] = $row['id'];
757  }
758  if (count($pout) > 0) {
759  if (count($pout) > 10) {
760  $pout = array_slice($pout, 0, 10);
761  $pout[] = '…';
762  }
763  $msg = sprintf("%d missing document%s in docread: <pre>{%s}</pre>", count($pout) , (count($pout) > 1 ? 's' : '') , join(', ', $pout));
764  } else $msg = "";
765  $this->tout["missing documents in docread"] = array(
766  "status" => (count($pout) == 0) ? self::OK : self::BOF,
767  "msg" => $msg
768  );
769  }
771  {
772  $result = pg_query($this->r, "SELECT id FROM docread WHERE id < 1e9 AND NOT EXISTS (SELECT 1 FROM doc WHERE docread.id = doc.id)");
773  $pout = array();
774  while ($row = pg_fetch_array($result, NULL, PGSQL_ASSOC)) {
775  $pout[] = $row['id'];
776  }
777  if (count($pout) > 0) {
778  if (count($pout) > 10) {
779  $pout = array_slice($pout, 0, 10);
780  $pout[] = '…';
781  }
782  $msg = sprintf("%d spurious document%s in docread: <pre>{%s}</pre>", count($pout) , (count($pout) > 1 ? 's' : '') , join(', ', $pout));
783  } else $msg = "";
784  $this->tout["spurious documents in docread"] = array(
785  "status" => (count($pout) == 0) ? self::OK : self::BOF,
786  "msg" => $msg
787  );
788  }
789 }
static verifyDbFamily($famid, NormalAttribute $aoa=null)
static getOrphanAttributes($famid)
const OK
getUnreferencedPermission()
Exception class use exceptionCode to identifiy correctly exception.
Definition: exceptions.php:19
checkStandardConformingStrings()
checkMultipleAlive()
$ret
checkConnection()
checkUnreferencedAcl()
checkUserAsGroup()
static isDroppedInNode(&$node, $column)
getSQLDropColumns(&$node, &$cmds=array(), $combined=true)
$drop
Definition: fdl_trigger.php:26
const BOF
computeDropColumns(&$node=null, $fromId=0)
$d
Definition: dav.php:77
checkAttributeType()
checkMissingDocumentsInDocread()
checkUnreferencedAction()
const KO
checkAttributeOrphan()
checkNetworkUser()
checkInheritance()
$conn
Definition: pginfo.php:29
checkUnreferenceUsers()
__construct($connect)
checkUnreferencedParameters()
new_Doc($dbaccess, $id= '', $latest=false)
checkDateStyle()
simpleQuery($dbaccess, $query, &$result=array(), $singlecolumn=false, $singleresult=false, $useStrict=null)
Definition: Lib.Common.php:484
if($file) if($subject==""&&$file) if($subject=="") $err
checkcleanContext()
$test
Definition: checkVault.php:30
$value
checkUnnamedFamilies()
checkSpuriousDocumentsInDocread()
← centre documentaire © anakeen