PHP_CompatInfo
[ class tree: PHP_CompatInfo ] [ index: PHP_CompatInfo ] [ all elements ]

Source for file CompatInfo.php

Documentation is available at CompatInfo.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available through the world-wide-web at the following url: |
  11. // | http://www.php.net/license/3_0.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Davey Shafik <davey@php.net> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: fsource_PHP_CompatInfo__CompatInfo.php.html,v 1.6 2004/04/26 16:23:31 davey Exp $
  20.  
  21.  
  22.  
  23. /**
  24. * Check Compatibility of chunk of PHP code
  25. * @package PHP_CompatInfo
  26. * @category PHP
  27. */
  28.  
  29. /**
  30. * Current PHP4 Version (used for -dev version)
  31. * @global string $php4_version
  32. */
  33. $php4_version = '4.3.6';
  34.  
  35. /**
  36. * Current PHP5 Version (used for -dev version)
  37. * @global string $php5_version
  38. */
  39. $php5_version = '5.0.0';
  40.  
  41. require_once 'PHP/data/func_array.php';
  42. require_once 'PHP/data/const_array.php';
  43.  
  44. // Seems to be a bug in PHP5RC2, $GLOBALS['const'] not reg'd
  45. $GLOBALS['const'] = $const;
  46. $GLOBALS['funcs'] = $funcs;
  47.  
  48. /**
  49. * Check Compatibility of chunk of PHP code
  50. *
  51. * @package PHP_CompatInfo
  52. * @author Davey Shafik <davey@php.net>
  53. * @copyright Copyright 2003 Davey Shafik and Synaptic Media. All Rights Reserved.
  54. * @example docs/examples/checkConstants.php Example that shows minimum version with Constants
  55. * @example docs/examples/parseFile.php Example on how to parse a file
  56. * @example docs/examples/parseDir.php Example on how to parse a directory
  57. * @example docs/examples/parseArray.php Example on using using parseArray() to parse a script
  58. * @example docs/examples/parseString.php Example on how to parse a string
  59. * @example docs/examples/Cli.php Example of using PHP_CompatInfo_Cli
  60. */
  61.  
  62. class PHP_CompatInfo {
  63.  
  64. /**
  65. * @var string Earliest version of PHP to use
  66. */
  67.  
  68. var $latest_version = '4.0.0';
  69.  
  70. /**
  71. * @var boolean Toggle parseDir recursion
  72. */
  73.  
  74. var $recurse_dir = true;
  75.  
  76. /**
  77. * Parse a file for its Compatibility info
  78. *
  79. * @param string $file Path of File to parse
  80. * @param array $options An array of options where:
  81. * 'debug' contains a boolean
  82. * to control whether extra
  83. * ouput is shown.
  84. * 'ignore_functions' contains an array
  85. * of functions to ignore when
  86. * calculating the version needed.
  87. * @access public
  88. * @return Array
  89. */
  90.  
  91. function parseFile($file, $options = array())
  92. {
  93. $options = array_merge(array('debug' => false),$options);
  94. if (!$tokens = $this->_tokenize($file)) {
  95. return false;
  96. }
  97. return $this->_parseTokens($tokens,$options);
  98. }
  99.  
  100. /**
  101. * Parse a string for its Compatibility info
  102. *
  103. * @param string $string PHP Code to parses
  104. * @param array $options An array of options where:
  105. * 'debug' contains a boolean
  106. * to control whether extra
  107. * ouput is shown.
  108. * 'ignore_functions' contains an array
  109. * of functions to ignore when
  110. * calculating the version needed.
  111. * @access public
  112. * @return Array
  113. */
  114.  
  115. function parseString($string, $options = array())
  116. {
  117. $options = array_merge(array('debug' => false),$options);
  118. if (!$tokens = $this->_tokenize($string,true)) {
  119. return false;
  120. }
  121. return $this->_parseTokens($tokens,$options);
  122. }
  123.  
  124. /**
  125. * Parse a directory recursively for its Compatibility info
  126. *
  127. * @see PHP_CompatInfo::_fileList()
  128. * @param string $dir Path of folder to parse
  129. * @param array $options Array of user options where:
  130. * 'file_ext' Contains an array of file
  131. * extensions to parse for PHP
  132. * code. Default: php, php4,
  133. * inc, phtml
  134. * 'recurse_dir' Boolean on whether to
  135. * recursively find files
  136. * 'debug' contains a boolean
  137. * to control whether extra
  138. * ouput is shown.
  139. * 'ignore_files' contains an array of
  140. * files to ignore. File
  141. * names are case insensitive.
  142. * 'ignore_dirs' contains an array of
  143. * directories to ignore.
  144. * Directory names are case
  145. * insensitive.
  146. * 'ignore_functions' contains an array
  147. * of functions to ignore when
  148. * calculating the version needed.
  149. * @access public
  150. * @return array
  151. */
  152.  
  153. function parseDir($dir,$options = array())
  154. {
  155. $files = array();
  156. $latest_version = $this->latest_version;
  157. $extensions = array();
  158. $constants = array();
  159. $ignored = array();
  160. $default_options = array('file_ext' => array('php','php4','inc','phtml'), 'recurse_dir' => true, 'debug' => false, 'ignore_file' => array(), 'ignore_dirs' => array());
  161. $options = array_merge($default_options,$options);
  162.  
  163. if($dir{strlen($dir)-1} == '/' || $dir{strlen($dir)-1} == '\\') {
  164. $dir = substr($dir,0,-1);
  165. }
  166. if(is_dir($dir) && is_readable($dir)) {
  167. if (isset($options['ignores_dirs'])) {
  168. $options['ignore_dirs'] = array_map("strtolower",$options['ignore_dirs']);
  169. } else {
  170. $options['ignore_dirs'] == array();
  171. }
  172. if (isset($options['ignore_files'])) {
  173. $options['ignore_files'] = array_map("strtolower",$options['ignore_files']);
  174. } else {
  175. $options['ignore_files'] = array();
  176. }
  177. $files_raw = $this->_fileList($dir,$options);
  178. foreach($files_raw as $file) {
  179. if(in_array(strtolower($file),$options['ignore_files'])) {
  180. $ignored[] = $file;
  181. continue;
  182. }
  183. $file_info = pathinfo($file);
  184. if (isset($file_info['extension']) && in_array($file_info['extension'],$options['file_ext'])) {
  185. $tokens = $this->_tokenize($file);
  186. $files[$file] = $this->_parseTokens($tokens,$options);
  187. }
  188. }
  189. foreach($files as $file) {
  190. $cmp = version_compare($latest_version,$file['version']);
  191. if ((int)$cmp === -1) {
  192. $latest_version = $file['version'];
  193. }
  194. foreach($file['extensions'] as $ext) {
  195. if(!in_array($ext,$extensions)) {
  196. $extensions[] = $ext;
  197. }
  198. }
  199. foreach ($file['constants'] as $const) {
  200. if(!in_array($const,$constants)) {
  201. $constants[] = $const;
  202. }
  203. }
  204. }
  205.  
  206. if (sizeof($files) < 1) {
  207. return false;
  208. }
  209.  
  210. $files['constants'] = $constants;
  211. $files['extensions'] = $extensions;
  212. $files['version'] = $latest_version;
  213. $files['ignored_files'] = $ignored;
  214.  
  215. return array_reverse($files);
  216. } else {
  217. return false;
  218. }
  219. }
  220.  
  221. /**
  222. * Alias of parseDir
  223. *
  224. * @uses PHP_CompatInfo::parseDir()
  225. * @access public
  226. */
  227.  
  228. function parseFolder($folder,$options = array()) {
  229. return $this->parseDir($folder,$options);
  230. }
  231.  
  232. /**
  233. * Parse an Array of Files
  234. *
  235. * You can parse an array of Files or Strings, to parse
  236. * strings, $options['is_string'] must be set to true
  237. *
  238. * @param array $files Array of file names or code strings
  239. * @param array $options An array of options where:
  240. * 'file_ext' Contains an array of file
  241. * extensions to parse for PHP
  242. * code. Default: php, php4,
  243. * inc, phtml
  244. * 'debug' contains a boolean
  245. * to control whether extra
  246. * ouput is shown.
  247. * 'is_string' contains a boolean
  248. * which says if the array values
  249. * are strings or file names.
  250. * 'ignore_files' contains an array of
  251. * files to ignore. File
  252. * names are case sensitive.
  253. * 'ignore_functions' contains an array
  254. * of functions to ignore when
  255. * calculating the version needed.
  256. * @access public
  257. * @return array
  258. */
  259.  
  260. function parseArray($files,$options = array()) {
  261. $latest_version = $this->latest_version;
  262. $extensions = array();
  263. $constants = array();
  264. $options = array_merge(array('file_ext' => array('php','php4','inc','phtml'), 'is_string' => false,'debug' => false, 'ignore_files' => array()),$options);
  265. $options['ignore_files'] = array_map("strtolower",$options['ignore_files']);
  266. foreach($files as $file) {
  267. if ($options['is_string'] == false) {
  268. $pathinfo = pathinfo($file);
  269. if (!in_array(strtolower($file),$options['ignore_files']) && in_array($pathinfo['extension'],$options['file_ext'])) {
  270. $tokens = $this->_tokenize($file,$options['is_string']);
  271. $files_parsed[$file] = $this->_parseTokens($tokens,$options);
  272. } else {
  273. $ignored[] = $file;
  274. }
  275. } else {
  276. $tokens = $this->_tokenize($file,$options['is_string']);
  277. $files_parsed[] = $this->_parseTokens($tokens,$options);
  278. }
  279. }
  280.  
  281. foreach($files_parsed as $file) {
  282. $cmp = version_compare($latest_version,$file['version']);
  283. if ((int)$cmp === -1) {
  284. $latest_version = $file['version'];
  285. }
  286. foreach($file['extensions'] as $ext) {
  287. if(!in_array($ext,$extensions)) {
  288. $extensions[] = $ext;
  289. }
  290. }
  291. foreach($file['constants'] as $const) {
  292. if(!in_array($const,$constants)) {
  293. $constants[] = $const;
  294. }
  295. }
  296. }
  297.  
  298. $files_parsed['constants'] = $constants;
  299. $files_parsed['extensions'] = $extensions;
  300. $files_parsed['version'] = $latest_version;
  301. $files_parsed['ignored_files'] = isset($ignored) ? $ignored : array();
  302. return array_reverse($files_parsed);
  303. }
  304.  
  305. /**
  306. * Parse the given Tokens
  307. *
  308. * The tokens are those returned by
  309. * token_get_all() which is nicely
  310. * wrapped in PHP_CompatInfo::_tokenize
  311. *
  312. * @param array $tokens Array of PHP Tokens
  313. * @param boolean $debug Show Extra Output
  314. * @access private
  315. * @return array
  316. */
  317.  
  318. function _parseTokens($tokens, $options)
  319. {
  320. $functions = array();
  321. $functions_version = array();
  322. $latest_version = $this->latest_version;
  323. $extensions = array();
  324. $constants = array();
  325. $constant_names = array();
  326. $udf = array();
  327. $token_count = sizeof($tokens);
  328. $i = 0;
  329. while ($i < $token_count) {
  330. $found_func = true;
  331. if ($tokens[$i][0] == T_FUNCTION) {
  332. $found_func = false;
  333. }
  334. while ($found_func == false) {
  335. $i += 1;
  336. if ($tokens[$i][0] == T_STRING) {
  337. $found_func = true;
  338. $udf[] = $tokens[$i][1];
  339. }
  340. }
  341. if ($tokens[$i][0] == T_STRING) {
  342. if (isset($tokens[$i + 1]) && ($tokens[$i + 1][0] == '(')) {
  343. $functions[] = $tokens[$i][1];
  344. }
  345. }
  346. if (in_array($tokens[$i][0],$GLOBALS['const']['tokens'])) {
  347. $constants[] = $tokens[$i][0];
  348. }
  349. $i += 1;
  350. }
  351.  
  352. $functions = array_unique($functions);
  353. if (isset($options['ignore_functions'])) {
  354. $options['ignore_functions'] = array_map("strtolower",$options['ignore_functions']);
  355. } else {
  356. $options['ignore_functions'] = array();
  357. }
  358. foreach($functions as $name) {
  359. if (isset($GLOBALS['funcs'][$name]) && (!in_array($name,$udf) && (!in_array($name,$options['ignore_functions'])))) {
  360. if ($options['debug'] == true) {
  361. $functions_version[$GLOBALS['funcs'][$name]['version_init']][] = array('function' => $name, 'extension' => $GLOBALS['funcs'][$name]['extension']);
  362. }
  363. $cmp = version_compare($latest_version,$GLOBALS['funcs'][$name]['version_init']);
  364. if ((int)$cmp === -1) {
  365. $latest_version = $GLOBALS['funcs'][$name]['version_init'];
  366. }
  367. if ((!empty($GLOBALS['funcs'][$name]['extension'])) && ($GLOBALS['funcs'][$name]['extension'] != 'ext_standard') && ($GLOBALS['funcs'][$name]['extension'] != 'zend')) {
  368. if(!in_array(substr($GLOBALS['funcs'][$name]['extension'],4),$extensions)) {
  369. $extensions[] = substr($GLOBALS['funcs'][$name]['extension'],4);
  370. }
  371. }
  372. }
  373. }
  374.  
  375. $constants = array_unique($constants);
  376. foreach($constants as $constant) {
  377. $cmp = version_compare($latest_version,$GLOBALS['const'][$constant]['version_init']);
  378. if ((int)$cmp === -1) {
  379. $latest_version = $GLOBALS['const'][$constant]['version_init'];
  380. }
  381. if(!in_array($GLOBALS['const'][$constant]['name'],$constant_names)) {
  382. $constant_names[] = $GLOBALS['const'][$constant]['name'];
  383. }
  384. }
  385.  
  386. ksort($functions_version );
  387.  
  388. $functions_version['constants'] = $constant_names;
  389. $functions_version['extensions'] = $extensions;
  390. $functions_version['version'] = $latest_version;
  391. $functions_version = array_reverse($functions_version);
  392. return $functions_version;
  393. }
  394.  
  395. /**
  396. * Token a file or string
  397. *
  398. * @param string $input Filename or PHP code
  399. * @param boolean $is_string Whether or note the input is a string
  400. * @access private
  401. * @return array
  402. */
  403.  
  404. function _tokenize($input,$is_string = false)
  405. {
  406. if ($is_string == false) {
  407. $input = file_get_contents($input,1);
  408. if (is_string($input)) {
  409. return token_get_all($input);
  410. }
  411. return false;
  412. } else {
  413. return token_get_all($input);
  414. }
  415. }
  416.  
  417. /**
  418. * Retrieve a listing of every file in $directory and
  419. * all subdirectories. Taken from PEAR_PackageFileManager_File
  420. *
  421. * @param string $directory full path to the directory you want the list of
  422. * @access private
  423. * @return array list of files in a directory
  424. */
  425.  
  426. function _fileList($directory,$options)
  427. {
  428. $ret = false;
  429. if (@is_dir($directory) && (!in_array(strtolower($directory),$options['ignore_dirs']))) {
  430. $ret = array();
  431. $d = @dir($directory);
  432. while($d && $entry=$d->read()) {
  433. if ($entry{0} != '.') {
  434. if (is_file($directory . DIRECTORY_SEPARATOR . $entry)) {
  435. $ret[] = $directory . DIRECTORY_SEPARATOR . $entry;
  436. }
  437. if (is_dir($directory . DIRECTORY_SEPARATOR . $entry) && ($options['recurse_dir'] != false)) {
  438. $tmp = $this->_fileList($directory . DIRECTORY_SEPARATOR . $entry,$options);
  439. if (is_array($tmp)) {
  440. foreach($tmp as $ent) {
  441. $ret[] = $ent;
  442. }
  443. }
  444. }
  445. }
  446. }
  447. if ($d) {
  448. $d->close();
  449. }
  450. } else {
  451. return false;
  452. }
  453.  
  454. return $ret;
  455. }
  456. }
  457.  
  458. ?>

Documentation generated on Mon, 26 Apr 2004 17:21:18 +0100 by phpDocumentor 1.3.0RC3