Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
check_requirements.php
1 <?php
29 error_reporting(E_ALL);
30 $SYSTEM_ROOT = '';
31 
32 if ((php_sapi_name() == 'cli')) {
33  if (isset($_SERVER['argv'][1])) {
34  $SYSTEM_ROOT = $_SERVER['argv'][1];
35  }
36 
37  $err_msg = "ERROR: You need to supply the path to the System Root as the first argument\n";
38 
39 } else {
40  if (isset($_GET['SYSTEM_ROOT'])) {
41  $SYSTEM_ROOT = $_GET['SYSTEM_ROOT'];
42  }
43 
44  $err_msg = '
45  <div style="background-color: red; color: white; font-weight: bold;">
46  You need to supply the path to the System Root as a query string variable called SYSTEM_ROOT
47  </div>
48  ';
49 }
50 
51 if (empty($SYSTEM_ROOT)) {
52  $err_msg .= "Usage: php install/check_requirements.php <PATH_TO_MATRIX>\n";
53  echo $err_msg;
54  exit();
55 }
56 
57 if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT.'/core/include/init.inc')) {
58  $err_msg = "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
59  $err_msg .= "Usage: php install/check_requirements.php <PATH_TO_MATRIX>\n";
60  echo $err_msg;
61  exit();
62 }
63 
69 if (ini_get('safe_mode') == 1) {
70  echo "MySource Matrix is not compatible with safe-mode.\n";
71  echo "You will need to disable safe_mode in your php.ini file(s).\n";
72  echo "\n";
73  echo "If your web server uses a different php.ini file to command line,\n";
74  echo " (this is the case if you're running a debian based system),\n";
75  echo " make sure you disable it in all php.ini files.\n";
76  echo "\n";
77  echo "Once you have done that, run this script again.\n";
78  exit(1);
79 }
80 
85 $missing_modules = array (
86  'php_extension' => array (
87  'required' => array(),
88  'suggested' => array(),
89  'out_of_date' => array(),
90  ),
91  'pear_package' => array (
92  'required' => array(),
93  'suggested' => array(),
94  'out_of_date' => array(),
95  ),
96  'pecl_package' => array (
97  'required' => array(),
98  'suggested' => array(),
99  'out_of_date' => array(),
100  ),
101  'external_program' => array (
102  'required' => array(),
103  'suggested' => array(),
104  'out_of_date' => array(),
105  ),
106  'php_file' => array (
107  'required' => array(),
108  'suggested' => array(),
109  'out_of_date' => array(),
110  ),
111 );
112 
116 check_requirement_file($SYSTEM_ROOT.'/core/assets/requirements.xml', 'core');
117 
124 $xml_files = get_files($SYSTEM_ROOT . '/packages', 'requirements.xml', 2);
125 foreach ($xml_files as $xml_file) {
126  $package_path = str_replace($SYSTEM_ROOT.'/packages/', '', $xml_file);
127 
138  $pkg_info = explode('/', $package_path);
139  array_pop($pkg_info);
140  $package_name = implode('/', $pkg_info);
141  check_requirement_file($xml_file, $package_name);
142 }
143 
150 $anything_missing = false;
151 
152 $check_types = array_keys($missing_modules);
153 foreach ($check_types as $check_type) {
154  $types = array_keys($missing_modules[$check_type]);
155 
156  switch ($check_type)
157  {
158  case 'php_extension':
159  $prefix = 'These php extensions are ';
160  break;
161  case 'pear_package':
162  $prefix = 'These pear packages are ';
163  break;
164  case 'pecl_package':
165  $prefix = 'These pecl packages are ';
166  break;
167  case 'external_program':
168  $prefix = 'These external programs are ';
169  break;
170  case 'php_file':
171  $prefix = 'These external php scripts are ';
172  break;
173  }
174 
175  foreach ($types as $type) {
176  if (empty($missing_modules[$check_type][$type])) {
177  continue;
178  }
179 
180  if ($anything_missing === false) {
181  echo "The following requirements or suggestions are made:\n\n";
182  $anything_missing = true;
183  }
184 
185  switch ($type)
186  {
187  case 'required':
188  case 'suggested':
189  $heading = $type;
190  $suffix = " by the %s package";
191  break;
192  case 'out_of_date':
193  $heading = "found, but out of date";
194  $suffix = " for the %s package";
195  break;
196  }
197 
202  $list = array();
203 
204  foreach ($missing_modules[$check_type][$type] as $item) {
205  $req_by = $item['required_by'];
206  if (!isset($list[$req_by])) {
207  $list[$req_by] = array();
208  }
209  unset($item['required_by']);
210  $list[$req_by][] = $item;
211  sort($list[$req_by]);
212  }
213 
214  asort($list);
215 
216  foreach ($list as $req_by => $details) {
217  printf($prefix . $heading . $suffix . "\n", $req_by);
218  echo str_repeat('-', 20) . "\n";
219  foreach ($details as $item) {
220  echo "\t" . $item['name'];
221  if (isset($item['version_found'])) {
222  echo " (Found version " . $item['version_found'] . " but require at least " . $item['version_required'] . ")";
223  }
224  echo "\n";
225  }
226  echo "\n";
227  }
228  }
229 }
230 
234 if (!$anything_missing) {
235  echo "Everything appears to be available and up to date.\n";
236 }
237 
249 function check_requirement_file($file='', $package_name='core')
250 {
251  if (!is_file($file)) {
252  trigger_error("File '".$file."' doesn't exist", E_USER_WARNING);
253  return;
254  }
255 
256  try {
257  $requirement_list = new SimpleXMLElement($file, LIBXML_NOCDATA, TRUE);
258  } catch (Exception $e) {
259  trigger_error('Could not parse requirements XML file (' . $file . '): '.$e->getMessage(), E_USER_WARNING);
260  return;
261  }
262 
263  foreach ($requirement_list->requirement as $requirement_check) {
264  check_requirement($requirement_check, $package_name);
265  }
266 }
267 
303 function check_requirement($requirement_check, $package_name='core')
304 {
305  global $missing_modules;
306 
310  static $pear_package_list = array();
311  static $pecl_package_list = array();
312  static $php_extension_list = array();
313 
314  if (empty($pear_package_list)) {
315  $rc = -1;
316  $pear_list = array();
317  exec('pear list 2>/dev/null', $pear_list, $rc);
318 
322  if (empty($pear_list) || $rc !== 0) {
323  $msg = "Unable to exec the 'pear list' command.\n";
324  $msg .= "Please check pear is installed and in your path then try again.\n";
325  echo $msg;
326  exit(1);
327  }
328 
338  unset($pear_list[0]);
339  unset($pear_list[1]);
340  unset($pear_list[2]);
341 
349  foreach ($pear_list as $line) {
350  $line = preg_replace('/\s+/', ' ', $line);
351  list($name, $version, $state) = explode(' ', $line);
352  $pear_package_list[strtolower($name)] = $version;
353  }
354  }
355 
356  if (empty($pecl_package_list)) {
357  $rc = -1;
358  $pecl_list = array();
359  exec('pecl list 2>/dev/null', $pecl_list, $rc);
360 
364  if (empty($pecl_list) || $rc !== 0) {
365  $msg = "Unable to exec the 'pecl list' command.\n";
366  $msg .= "Please check pecl is installed and in your path then try again.\n";
367  echo $msg;
368  exit(1);
369  }
370 
380  unset($pecl_list[0]);
381  unset($pecl_list[1]);
382  unset($pecl_list[2]);
383 
391  foreach ($pecl_list as $line) {
392  $line = preg_replace('/\s+/', ' ', $line);
393  list($name, $version, $state) = explode(' ', $line);
394  $pecl_package_list[strtolower($name)] = $version;
395  }
396  }
397 
398  if (empty($php_extension_list)) {
399  $php_extension_list = get_loaded_extensions();
400  }
401 
402  $check_type = null;
403  if (isset($requirement_check->php_extension)) {
404  $check_type = 'php_extension';
405  }
406 
407  if (isset($requirement_check->pear_package)) {
408  $check_type = 'pear_package';
409  }
410 
411  if (isset($requirement_check->pecl_package)) {
412  $check_type = 'pecl_package';
413  }
414 
415  if (isset($requirement_check->external_program)) {
416  $check_type = 'external_program';
417  }
418 
419  if (isset($requirement_check->php_file)) {
420  $check_type = 'php_file';
421  }
422 
423  $check_ok = false;
424  $check_alternative = true;
425  $check_version = false;
426 
427  $extra_info = '';
428 
429  $description = '';
430  if ($requirement_check->description) {
431  $description = (string)$requirement_check->description;
432  }
433 
434  switch ($check_type)
435  {
436  case 'php_extension':
437  $check_name = (string)$requirement_check->php_extension;
438  if (in_array($check_name, $php_extension_list)) {
439  $check_ok = true;
440  if (!$requirement_check->suggested) {
441  $check_alternative = false;
442  }
443  if ($requirement_check->version) {
444  $check_version = true;
445  $version_found = phpversion($check_name);
446  $version_required = (string)$requirement_check->version;
447  }
448  break;
449  }
450  break;
451 
452  case 'pear_package':
453  $check_name = strtolower($requirement_check->pear_package);
454 
455  if (isset($pear_package_list[$check_name])) {
456  $check_version = true;
457  $check_ok = true;
458  $version_found = $pear_package_list[$check_name];
459  $version_required = (string)$requirement_check->version;
460  }
461  break;
462 
463  case 'pecl_package':
464  $check_name = strtolower($requirement_check->pecl_package);
465 
466  if (isset($pecl_package_list[$check_name])) {
467  $check_version = true;
468  $check_ok = true;
469  $version_found = $pecl_package_list[$check_name];
470  $version_required = (string)$requirement_check->version;
471  }
472  break;
473 
474  case 'external_program':
475  $external_program = (string)$requirement_check->external_program;
476  $program_path = '';
477  if (isset($requirement_check->path)) {
478  $program_path = (string)$requirement_check->path;
479  $program_path = rtrim($program_path, '/').'/';
480  }//end if
481 
482  $version_required = (string)$requirement_check->version;
483 
484  $cmd = $program_path.$external_program;
485  $check_name = $external_program;
486 
487  if ($external_program === 'padre-iw') {
488  if (!empty($program_path) && is_dir($program_path)) {
489  $cmd = 'export SEARCH_HOME='.dirname($program_path).';'.$cmd;
490  }
491  }
492 
493  if (isset($requirement_check->version_arguments)) {
494  $cmd .= ' ' . escapeshellarg((string)$requirement_check->version_arguments);
495  }
496 
497  if (isset($requirement_check->uses_stderr)) {
498  $cmd .= ' 2>&1';
499  } else {
503  $cmd .= ' 2>/dev/null';
504  }
505 
506  $cmd_output = array();
507  $cmd_return_code = -1;
508  exec($cmd, $cmd_output, $cmd_return_code);
509 
510  $expected_return_code = 0;
511  if (isset($requirement_check->expected_return_code)) {
512  $expected_return_code = $requirement_check->expected_return_code;
513  }
514 
520  if ($cmd_return_code != $expected_return_code || empty($cmd_output)) {
521  break;
522  }
523 
524  $check_version = true;
525 
531  switch ($external_program)
532  {
550  case 'pdftohtml':
551  $check_ok = true;
552 
556  $check_version = false;
557 
558  $version_line = $cmd_output[0];
562  list($intro, $version_kw, $version_found) = explode(' ', $version_line);
563 
564  $version_info = explode('.', $version_found);
565 
566  // If it's 'a.b' we can directly check that.
567  if (count($version_info) == 2) {
568  $version_check = version_compare($version_found, $version_required, '>=');
569  if ($version_check !== true) {
570  $missing_modules['external_program']['out_of_date'][] = array(
571  'name' => $external_program,
572  'version_found' => $version_found,
573  'version_required' => $version_required,
574  'required_by' => $package_name,
575  );
576  }
577  } else {
578  // It's 'a.b.c', we'll check ourselves.
579  // We'll check the copyright line, make sure it mentions 2009.
580  // If it does, we're good to go, if it doesn't, we're out of date.
581  $_found = FALSE;
582  foreach ($cmd_output as $output_line) {
583  if (strpos($output_line, 'Copyright 2005-2009') !== FALSE) {
584  $_found = TRUE;
585  break;
586  }
587  }
588 
589  if ($_found === FALSE) {
590  $missing_modules['external_program']['out_of_date'][] = array(
591  'name' => $external_program,
592  'version_found' => $version_found,
593  'version_required' => $version_required,
594  'required_by' => $package_name,
595  );
596  }
597  }
598  break;
599 
607  case 'tidy':
612  $check_version = false;
613 
614  $version_line = $cmd_output[0];
618  $match_found = preg_match('/released on (.*)$/', $version_line, $matches);
619  if (!$match_found) {
620  $extra_info = " (version checking not working)";
621  break;
622  }
623  $check_ok = true;
624 
632  $version_found = $matches[1];
633  $version_found_date = strtotime($version_found);
634  $version_required_date = strtotime($version_required);
635 
636  if ($version_found_date < $version_required_date) {
637  $missing_modules['external_program']['out_of_date'][] = array(
638  'name' => $external_program,
639  'version_found' => $version_found,
640  'version_required' => $version_required,
641  'required_by' => $package_name,
642  );
643  }
644  break;
645 
659  case 'antiword':
660  if (!isset($cmd_output[3])) {
661  $extra_info = " (version checking not working)";
662  break;
663  }
664 
665  $version_line = $cmd_output[3];
666  $match_found = preg_match('/Version: (.*?)\s+/', $version_line, $matches);
667  if ($match_found) {
668  $check_ok = true;
669  $version_found = $matches[1];
670  } else {
671  $extra_info = " (version checking not working)";
672  }
673  break;
674 
683  case 'squidclient':
684  $check_ok = true;
685  $check_version = false;
686  break;
687 
694  case 'clamscan':
695  $version_line = $cmd_output[0];
696  $match_found = preg_match('%ClamAV (.*?)/%', $version_line, $matches);
697  if ($match_found) {
698  $check_ok = true;
699  $version_found = $matches[1];
700  } else {
701  $extra_info = " (version checking not working)";
702  }
703  break;
704 
715  case 'fpscan':
716  if (!isset($cmd_output[1])) {
717  $extra_info = " (version checking not working)";
718  break;
719  }
720  $version_line = $cmd_output[1];
721  $match_found = preg_match('/ version (.*?) /', $version_line, $matches);
722  if ($match_found) {
723  $check_ok = true;
724  $version_found = $matches[1];
725  } else {
726  $extra_info = " (version checking not working)";
727  }
728 
729  break;
730 
738  case 'padre-iw':
739  if (!isset($cmd_output[0])) {
740  $extra_info = " (version checking not working)";
741  break;
742  }
743  $version_line = $cmd_output[0];
744  $match_found = preg_match('/FUNNELBACK_PADRE_([0-9\.]*)/', $version_line, $matches);
745  if ($match_found) {
746  $check_ok = true;
747  $version_found = $matches[1];
748  } else {
749  $extra_info = " (version checking not working)";
750  }
751 
752  break;
753 
759  case 'js':
760  $check_ok = true;
761  $version_line = $cmd_output[0];
762  list($junk, $version_found, $date) = explode(' ', $version_line);
763  break;
764 
765  default:
766  $missing_modules['external_program']['required'][] = array (
767  'name' => $external_program . " (Unknown program, can't check version numbers)",
768  'required_by' => $package_name,
769  );
770  return;
771  break;
772 
773  }
774  break;
775 
776  case 'php_file':
777  $check_version = false;
778 
779  $php_file = (string)$requirement_check->php_file;
780 
781  $check_name = $php_file;
782 
783  if (is_file($php_file)) {
784  $check_ok = true;
785  } else {
786  $extra_info = " (only the php include_path was checked, if it is not in one of those paths the file has not been found)";
787  }
788  break;
789 
790  case null:
791  echo "Unknown type ('" . $check_type . "')\n";
792  return;
793  break;
794 
795  }
796 
797  if ($check_version) {
798  $version_check = version_compare($version_found, $version_required, '>=');
799  if ($version_check !== true) {
800  $missing_modules[$check_type]['out_of_date'][] = array(
801  'name' => $check_name . $description . $extra_info,
802  'version_found' => $version_found,
803  'version_required' => $version_required,
804  'required_by' => $package_name
805  );
806  }
807  }
808 
809  $alternative_ok = null;
810  $alternative_suggested = false;
816  if ($check_alternative && $requirement_check->alternative) {
817  $alternative_suggested = $requirement_check->alternative->suggested;
818  $alternative_ok = check_requirement($requirement_check->alternative, $package_name);
819  }
820 
825  if ($alternative_ok !== null) {
833  if (!$alternative_suggested && !$check_ok) {
834  $check_ok = $alternative_ok;
835  }
836  }
837 
838  if (!$check_ok) {
839  if ($requirement_check->suggested) {
840  $missing_modules[$check_type]['suggested'][] = array(
841  'name' => $check_name . $description . $extra_info,
842  'required_by' => $package_name
843  );
844  } else {
845  $missing_modules[$check_type]['required'][] = array(
846  'name' => $check_name . $description . $extra_info,
847  'required_by' => $package_name
848  );
849  }
850  }
851 
852  return $check_ok;
853 }
854 
867 function get_files($dir='', $filename='', $max_depth=0, $_depth=0)
868 {
869  $list = array();
870  if (empty($dir) || empty($filename)) {
871  return $list;
872  }
873 
874  if (!is_dir($dir)) {
875  return $list;
876  }
877 
878  if ($max_depth > 0 && $_depth > $max_depth) {
879  return $list;
880  }
881 
882  $d = dir($dir);
883 
884  while (FALSE !== ($entry = $d->read())) {
885  if ($entry == '.' || $entry == '..') {
886  continue;
887  }
888 
889  if (is_dir($dir.'/'.$entry)) {
890  $sub_list = get_files($dir.'/'.$entry, $filename, $max_depth, ($_depth+1));
891  $list = array_merge($sub_list, $list);
892  continue;
893  }
894 
895  if ($entry == $filename) {
896  $list[] = $dir.'/'.$entry;
897  }
898  }
899  $d->close();
900  return $list;
901 }
902