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

Source for file Parser.php

Documentation is available at Parser.php

  1. <?php
  2. /**
  3.  * Copyright (c) 2008, Davey Shafik <davey@php.net>
  4.  *                     Laurent Laville <pear@laurent-laville.org>
  5.  *
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  *
  12.  *     * Redistributions of source code must retain the above copyright
  13.  *       notice, this list of conditions and the following disclaimer.
  14.  *     * Redistributions in binary form must reproduce the above copyright
  15.  *       notice, this list of conditions and the following disclaimer in the
  16.  *       documentation and/or other materials provided with the distribution.
  17.  *     * Neither the name of the authors nor the names of its contributors
  18.  *       may be used to endorse or promote products derived from this software
  19.  *       without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  25.  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31.  * POSSIBILITY OF SUCH DAMAGE.
  32.  *
  33.  * PHP versions 4 and 5
  34.  *
  35.  * @category PHP
  36.  * @package  PHP_CompatInfo
  37.  * @author   Davey Shafik <davey@php.net>
  38.  * @author   Laurent Laville <pear@laurent-laville.org>
  39.  * @license  http://www.opensource.org/licenses/bsd-license.php  BSD
  40.  * @version  CVS: $Id: Parser.php,v 1.11 2008/07/22 20:26:19 farell Exp $
  41.  * @link     http://pear.php.net/package/PHP_CompatInfo
  42.  * @since    File available since Release 1.8.0b2
  43.  */
  44.  
  45. require_once 'Event/Dispatcher.php';
  46. require_once 'File/Find.php';
  47.  
  48. /**
  49.  * An array of function init versions and extension
  50.  */
  51. require_once 'PHP/CompatInfo/func_array.php';
  52.  
  53. /**
  54.  * An array of constants and their init versions
  55.  */
  56. require_once 'PHP/CompatInfo/const_array.php';
  57.  
  58. /**
  59.  * An abstract base class for CompatInfo renderers
  60.  */
  61. require_once 'PHP/CompatInfo/Renderer.php';
  62.  
  63. /**
  64.  * Event name of parsing data source start process
  65.  */
  66. define('PHP_COMPATINFO_EVENT_AUDITSTARTED''auditStarted');
  67. /**
  68.  * Event name of parsing data source end process
  69.  */
  70. define('PHP_COMPATINFO_EVENT_AUDITFINISHED''auditFinished');
  71. /**
  72.  * Event name of parsing a file start process
  73.  */
  74. define('PHP_COMPATINFO_EVENT_FILESTARTED''fileStarted');
  75. /**
  76.  * Event name of parsing a file end process
  77.  */
  78. define('PHP_COMPATINFO_EVENT_FILEFINISHED''fileFinished');
  79. /**
  80.  * Event name of parsing a file start process
  81.  */
  82. define('PHP_COMPATINFO_EVENT_CODESTARTED''codeStarted');
  83. /**
  84.  * Event name of parsing a file end process
  85.  */
  86. define('PHP_COMPATINFO_EVENT_CODEFINISHED''codeFinished');
  87.  
  88. /**
  89.  * Parser logic
  90.  *
  91.  * This class is the model in the MVC design pattern of API 1.8.0 (since beta 2)
  92.  *
  93.  * @category PHP
  94.  * @package  PHP_CompatInfo
  95.  * @author   Laurent Laville <pear@laurent-laville.org>
  96.  * @license  http://www.opensource.org/licenses/bsd-license.php  BSD
  97.  * @version  Release: 1.8.0
  98.  * @link     http://pear.php.net/package/PHP_CompatInfo
  99.  * @since    Class available since Release 1.8.0b2
  100.  */
  101. {
  102.     /**
  103.      * Instance of concrete renderer used to show parse results
  104.      *
  105.      * @var    object 
  106.      * @since  1.8.0b2
  107.      * @access protected
  108.      */
  109.     var $renderer;
  110.  
  111.     /**
  112.      * Stores the event dispatcher which handles notifications
  113.      *
  114.      * @var    object 
  115.      * @since  1.8.0b2
  116.      * @access protected
  117.      */
  118.     var $dispatcher;
  119.  
  120.     /**
  121.      * Count the number of observer registered.
  122.      * The Event_Dispatcher will be add on first observer registration, and
  123.      * will be removed with the last observer.
  124.      *
  125.      * @var    integer 
  126.      * @since  1.8.0b2
  127.      * @access private
  128.      */
  129.     var $_observerCount;
  130.  
  131.     /**
  132.      * @var string Earliest version of PHP to use
  133.      * @since  0.7.0
  134.      */
  135.     var $latest_version = '4.0.0';
  136.  
  137.     /**
  138.      * @var string Last version of PHP to use
  139.      */
  140.     var $earliest_version = '';
  141.  
  142.     /**
  143.      * @var array Parsing options
  144.      */
  145.     var $options;
  146.  
  147.     /**
  148.      * @var array Data Source
  149.      * @since  1.8.0b2
  150.      */
  151.     var $dataSource;
  152.  
  153.     /**
  154.      * @var array Directory list found when parsing data source
  155.      * @since  1.8.0b2
  156.      * @see    getDirlist()
  157.      */
  158.     var $directories;
  159.  
  160.     /**
  161.      * @var array List of files ignored when parsing data source
  162.      * @since  1.8.0b2
  163.      * @see    getIgnoredFiles()
  164.      */
  165.     var $ignored_files = array();
  166.  
  167.     /**
  168.      * Class constructor (ZE1) for PHP4
  169.      *
  170.      * @access public
  171.      * @since  version 1.8.0b2 (2008-06-03)
  172.      */
  173.     function PHP_CompatInfo_Parser()
  174.     {
  175.         $this->__construct();
  176.     }
  177.  
  178.     /**
  179.      * Class constructor (ZE2) for PHP5+
  180.      *
  181.      * @access public
  182.      * @since  version 1.8.0b2 (2008-06-03)
  183.      */
  184.     function __construct()
  185.     {
  186.         $this->options = array(
  187.             'file_ext' => array('php''php4''inc''phtml'),
  188.             'recurse_dir' => true,
  189.             'debug' => false,
  190.             'is_string' => false,
  191.             'ignore_files' => array(),
  192.             'ignore_dirs' => array()
  193.             );
  194.     }
  195.  
  196.     /**
  197.      * Set up driver to be used
  198.      *
  199.      * Set up driver to be used, dependant on specified type.
  200.      *
  201.      * @param string $type Name the type of driver (html, text...)
  202.      * @param array  $conf A hash containing any additional configuration
  203.      *
  204.      * @access public
  205.      * @return void 
  206.      * @since  version 1.8.0b2 (2008-06-03)
  207.      */
  208.     function setOutputDriver($type$conf = array())
  209.     {
  210.         $this->renderer =PHP_CompatInfo_Renderer::factory($this$type$conf);
  211.     }
  212.  
  213.     /**
  214.      * Registers a new listener
  215.      *
  216.      * Registers a new listener with the given criteria.
  217.      *
  218.      * @param mixed  $callback A PHP callback
  219.      * @param string $nName    (optional) Expected notification name
  220.      *
  221.      * @access public
  222.      * @return void 
  223.      * @since  version 1.8.0b2 (2008-06-03)
  224.      */
  225.     function addListener($callback$nName = EVENT_DISPATCHER_GLOBAL)
  226.     {
  227.         $this->dispatcher =Event_Dispatcher::getInstance();
  228.         // $this->dispatcher->setNotificationClass('PHP_CompatInfo_Audit');
  229.         $this->dispatcher->addObserver($callback$nName);
  230.         $this->_observerCount++;
  231.     }
  232.  
  233.     /**
  234.      * Removes a registered listener
  235.      *
  236.      * Removes a registered listener that correspond to the given criteria.
  237.      *
  238.      * @param mixed  $callback A PHP callback
  239.      * @param string $nName    (optional) Expected notification name
  240.      *
  241.      * @access public
  242.      * @return bool  True if listener was removed, false otherwise.
  243.      * @since  version 1.8.0b2 (2008-06-03)
  244.      */
  245.     function removeListener($callback$nName = EVENT_DISPATCHER_GLOBAL)
  246.     {
  247.         $result $this->dispatcher->removeObserver($callback$nName);
  248.  
  249.         if ($result{
  250.             $this->_observerCount--;
  251.             if ($this->_observerCount == 0{
  252.                 unset($this->dispatcher);
  253.             }
  254.         }
  255.         return $result;
  256.     }
  257.  
  258.     /**
  259.      * Post a new notification to all listeners registered.
  260.      *
  261.      * This notification occured only if a dispatcher exists. That means if
  262.      * at least one listener was registered.
  263.      *
  264.      * @param string $event Name of the notification handler
  265.      * @param array  $info  (optional) Additional information about the notification
  266.      *
  267.      * @access public
  268.      * @return void 
  269.      * @since  version 1.8.0b2 (2008-06-03)
  270.      */
  271.     function notifyListeners($event$info = array())
  272.     {
  273.         if (isset($this->dispatcher)) {
  274.             $this->dispatcher->post($this$event$info);
  275.         }
  276.     }
  277.  
  278.     /**
  279.      * Load components list
  280.      *
  281.      * Load components list for a PHP version or subset
  282.      *
  283.      * @param string         $min           PHP minimal version
  284.      * @param string|boolean$max           (optional) PHP maximal version
  285.      * @param boolean        $include_const (optional) include constants list
  286.      *                                                  in final result
  287.      * @param boolean        $groupby_vers  (optional) give initial php version
  288.      *                                                  of function or constant
  289.      *
  290.      * @return array         An array of php function/constant names history
  291.      * @access public
  292.      * @static
  293.      * @since  version 1.2.0 (2006-08-23)
  294.      */
  295.     function loadVersion($min$max = false,
  296.                          $include_const = false$groupby_vers = false)
  297.     {
  298.         $keys = array();
  299.         foreach ($GLOBALS['_PHP_COMPATINFO_FUNCS'as $func => $arr{
  300.             if (isset($arr['pecl']&& $arr['pecl'=== true{
  301.                 continue;
  302.             }
  303.             $vmin $arr['init'];
  304.             if (version_compare($vmin$min< 0{
  305.                 continue;
  306.             }
  307.             if ($max{
  308.                 $end (isset($arr['end'])) $arr['end'$vmin;
  309.  
  310.                 if (version_compare($end$max< 1{
  311.                     if ($groupby_vers === true{
  312.                         $keys[$vmin][$func;
  313.                     else {
  314.                         $keys[$func;
  315.                     }
  316.                 }
  317.             else {
  318.                 if ($groupby_vers === true{
  319.                     $keys[$vmin][$func;
  320.                 else {
  321.                     $keys[$func;
  322.                 }
  323.             }
  324.         }
  325.         ksort($keys);
  326.  
  327.         if ($include_const === true{
  328.             $keys = array('functions' => $keys'constants' => array());
  329.             foreach ($GLOBALS['_PHP_COMPATINFO_CONST'as $const => $arr{
  330.                 $vmin $arr['init'];
  331.                 if (version_compare($vmin$min< 0{
  332.                     continue;
  333.                 }
  334.                 if ($max{
  335.                     $end (isset($arr['end'])) $arr['end'$vmin;
  336.  
  337.                     if (version_compare($end$max< 1{
  338.                         if ($groupby_vers === true{
  339.                             $keys['constants'][$vmin][$arr['name'];
  340.                         else {
  341.                             $keys['constants'][$arr['name'];
  342.                         }
  343.                     }
  344.                 else {
  345.                     if ($groupby_vers === true{
  346.                         $keys['constants'][$vmin][$arr['name'];
  347.                     else {
  348.                         $keys['constants'][$arr['name'];
  349.                     }
  350.                 }
  351.             }
  352.             ksort($keys['constants']);
  353.         }
  354.         return $keys;
  355.     }
  356.  
  357.     /**
  358.      * Returns list of directory parsed
  359.      *
  360.      * Returns list of directory parsed, depending of restrictive parser options.
  361.      *
  362.      * @param mixed $dir     The directory name
  363.      * @param array $options An array of parser options. See parseData() method.
  364.      *
  365.      * @access public
  366.      * @return array   list of directories that should be parsed
  367.      * @since  version 1.8.0b2 (2008-06-03)
  368.      */
  369.     function getDirlist($dir$options)
  370.     {
  371.         if (!isset($this->directories)) {
  372.             $this->getFilelist($dir$options);
  373.         }
  374.  
  375.         return $this->directories;
  376.     }
  377.  
  378.     /**
  379.      * Returns list of files parsed
  380.      *
  381.      * Returns list of files parsed, depending of restrictive parser options.
  382.      *
  383.      * @param mixed $dir     The directory name where to look files
  384.      * @param array $options An array of parser options. See parseData() method.
  385.      *
  386.      * @access public
  387.      * @return array   list of files that should be parsed
  388.      * @since  version 1.8.0b2 (2008-06-03)
  389.      */
  390.     function getFilelist($dir$options)
  391.     {
  392.         $skipped = array();
  393.         $ignored = array();
  394.  
  395.         $options             array_merge($this->options$options);
  396.         $options['file_ext'array_map('strtolower'$options['file_ext']);
  397.  
  398.         if ($dir{strlen($dir)-1== '/' || $dir{strlen($dir)-1== '\\'{
  399.             $dir substr($dir0-1);
  400.         }
  401.  
  402.         // use system directory separator rather than forward slash by default
  403.         $ff         = new File_Find();
  404.         $ff->dirsep = DIRECTORY_SEPARATOR;
  405.  
  406.         // get directory list that should be ignored from scope
  407.         $ignore_dirs = array();
  408.         if (count($options['ignore_dirs']> 0{
  409.             foreach ($options['ignore_dirs'as $cond{
  410.                 $cond        str_replace('\\'"\\\\"$cond);
  411.                 $dirs        $ff->search('`'.$cond.'`'$dir'perl',
  412.                                            true'directories');
  413.                 $ignore_dirs array_merge($ignore_dirs$dirs);
  414.             }
  415.         }
  416.  
  417.         // get file list that should be ignored from scope
  418.         $ignore_files = array();
  419.         if (count($options['ignore_files']> 0{
  420.             foreach ($options['ignore_files'as $cond{
  421.                 $cond         str_replace('\\'"\\\\"$cond);
  422.                 $files        $ff->search('`'.$cond.'`'$dir'perl',
  423.                                             true'files');
  424.                 $ignore_files array_merge($ignore_files$files);
  425.             }
  426.         }
  427.  
  428.         list($directories$files$ff->maptree($dir);
  429.  
  430.         foreach ($files as $file{
  431.  
  432.             $file_info pathinfo($file);
  433.             if ($options['recurse_dir'== false
  434.                 && $file_info['dirname'!= $dir{
  435.                 $skipped[$file;
  436.                 continue;
  437.             }
  438.             if (in_array($file_info['dirname']$ignore_dirs)) {
  439.                 $ignored[$file;
  440.  
  441.             elseif (in_array($file$ignore_files)) {
  442.                 $ignored[$file;
  443.  
  444.             else {
  445.                 if (isset($file_info['extension'])
  446.                     && in_array(strtolower($file_info['extension']),
  447.                                 $options['file_ext'])) {
  448.                     continue;
  449.                 }
  450.                 $ignored[$file;
  451.             }
  452.         }
  453.  
  454.         $files PHP_CompatInfo_Parser::_arrayDiff($files,
  455.                                                    array_merge($ignored$skipped));
  456.         $this->directories
  457.                = PHP_CompatInfo_Parser::_arrayDiff($directories$ignore_dirs);
  458.         $this->ignored_files
  459.                = $ignored;
  460.  
  461.         return $files;
  462.     }
  463.  
  464.     /**
  465.      * Returns list of files ignored
  466.      *
  467.      * Returns list of files ignored while parsing directories
  468.      *
  469.      * @access public
  470.      * @return array or false on error
  471.      * @since  version 1.8.0b2 (2008-06-03)
  472.      */
  473.     function getIgnoredFiles()
  474.     {
  475.         return $this->ignored_files;
  476.     }
  477.  
  478.     /**
  479.      * Parse a data source
  480.      *
  481.      * Parse a data source with auto detect ability. This data source, may be
  482.      * one of these follows: a directory, a file, a string (chunk of code),
  483.      * an array of multiple origin.
  484.      *
  485.      * Each of five parsing functions support common and specifics options.
  486.      *
  487.      *  * Common options :
  488.      *  - 'debug'                   Contains a boolean to control whether
  489.      *                              extra ouput is shown.
  490.      *  - 'ignore_functions'        Contains an array of functions to ignore
  491.      *                              when calculating the version needed.
  492.      *  - 'ignore_constants'        Contains an array of constants to ignore
  493.      *                              when calculating the version needed.
  494.      *  - 'ignore_extensions'       Contains an array of php extensions to ignore
  495.      *                              when calculating the version needed.
  496.      *  - 'ignore_versions'         Contains an array of php versions to ignore
  497.      *                              when calculating the version needed.
  498.      *  - 'ignore_functions_match'  Contains an array of function patterns to ignore
  499.      *                              when calculating the version needed.
  500.      *  - 'ignore_extensions_match' Contains an array of extension patterns to ignore
  501.      *                              when calculating the version needed.
  502.      *  - 'ignore_constants_match'  Contains an array of constant patterns to ignore
  503.      *                              when calculating the version needed.
  504.      *
  505.      *  * parseArray, parseDir|parseFolder, specific options :
  506.      *  - 'file_ext'                Contains an array of file extensions to parse
  507.      *                              for PHP code. Default: php, php4, inc, phtml
  508.      *  - 'ignore_files'            Contains an array of files to ignore.
  509.      *                              File names are case insensitive.
  510.      *
  511.      *  * parseArray specific options :
  512.      *  - 'is_string'               Contains a boolean which says if the array values
  513.      *                              are strings or file names.
  514.      *
  515.      *  * parseDir|parseFolder specific options :
  516.      *  - 'recurse_dir'             Boolean on whether to recursively find files
  517.      *  - 'ignore_dirs'             Contains an array of directories to ignore.
  518.      *                              Directory names are case insensitive.
  519.      *
  520.      * @param mixed $dataSource The data source (may be file, dir, string, or array)
  521.      * @param array $options    An array of options. See above.
  522.      *
  523.      * @access public
  524.      * @return array or false on error
  525.      * @since  version 1.8.0b2 (2008-06-03)
  526.      */
  527.     function parseData($dataSource$options = array())
  528.     {
  529.         $this->options = array_merge($this->options$options);
  530.  
  531.         $dataType  gettype($dataSource);
  532.         $dataCount = 0;
  533.         // - when array source with mixed content incompatible
  534.         // - if all directories are not readable
  535.         // - if data source invalid type: other than file, directory, string
  536.  
  537.         if ($dataType == 'string' || $dataType == 'array'{
  538.             if (is_array($dataSource)) {
  539.                 //$dataType = 'array';
  540.             elseif (is_dir($dataSource)) {
  541.                 $dataType   'directory';
  542.                 $dataSource = array($dataSource);
  543.             elseif (is_file($dataSource)) {
  544.                 $dataType   'file';
  545.                 $dataSource = array($dataSource);
  546.             elseif (substr($dataSource05== '<?php'{
  547.                 //$dataType = 'string';
  548.                 $this->options = array_merge($this->options,
  549.                                              array('is_string' => true));
  550.                 $dataSource    = array($dataSource);
  551.             else {
  552.                 //$dataType = 'string';
  553.                 // directory or file are misspelled
  554.             }
  555.             if (is_array($dataSource)) {
  556.                 $dataSource $this->_validateDataSource($dataSource,
  557.                                                          $this->options);
  558.                 $dataCount  count($dataSource);
  559.             }
  560.         }
  561.  
  562.         $this->dataSource = array('dataSource' => $dataSource,
  563.                                   'dataType' => $dataType,
  564.                                   'dataCount' => $dataCount);
  565.  
  566.         $eventInfo array_merge($this->dataSource,
  567.                                  array('parseOptions' => $this->options));
  568.  
  569.         // notify all observers that parsing data source begin
  570.         $this->notifyListeners(PHP_COMPATINFO_EVENT_AUDITSTARTED$eventInfo);
  571.  
  572.         if ($dataCount == 0{
  573.             $parseData = false;
  574.         else {
  575.             switch ($dataType{
  576.             case 'array' :
  577.                 $parseData $this->_parseArray($dataSource$this->options);
  578.                 break;
  579.             case 'string' :
  580.                 $parseData $this->_parseString($dataSource$this->options);
  581.                 break;
  582.             case 'file' :
  583.                 $parseData $this->_parseFile($dataSource$this->options);
  584.                 break;
  585.             case 'directory' :
  586.                 $parseData $this->_parseDir($dataSource$this->options);
  587.                 break;
  588.             }
  589.         }
  590.  
  591.         // notify all observers that parsing data source is over
  592.         $this->notifyListeners(PHP_COMPATINFO_EVENT_AUDITFINISHED$parseData);
  593.  
  594.         return $parseData;
  595.     }
  596.  
  597.     /**
  598.      * Validate content of data source
  599.      *
  600.      * Validate content of data source list, before parsing each source
  601.      *
  602.      * @param mixed $dataSource The data source (may be file, dir, or string)
  603.      * @param array $options    Parser options (see parseData() method for details)
  604.      *
  605.      * @access private
  606.      * @return array   empty array on error
  607.      * @since  version 1.8.0b3 (2008-06-07)
  608.      */
  609.     function _validateDataSource($dataSource$options = array())
  610.     {
  611.         /**
  612.          * Array by default expect to contains list of files and/or directories.
  613.          * If you want a list of chunk of code (strings), 'is_string' option
  614.          * must be set to true.
  615.          */
  616.         $list = array();
  617.  
  618.         foreach ($dataSource as $source{
  619.             if ($options['is_string'=== true{
  620.                 if (is_string($source)) {
  621.                     $list[$source;
  622.                 else {
  623.                     /**
  624.                      * One of items is not a string (chunk of code). All
  625.                      * data sources parsing are stopped and considered as invalid.
  626.                      */
  627.                     $list = array();
  628.                     break;
  629.                 }
  630.             else {
  631.                 if (is_dir($source&& is_readable($source)) {
  632.                     $files $this->getFilelist($source$options);
  633.                     $list  array_merge($list$files);
  634.                 elseif (is_file($source)) {
  635.                     $list[$source;
  636.                 else {
  637.                     /**
  638.                      * One of items is not a valid file or directory. All
  639.                      * data sources parsing are stopped and considered as invalid.
  640.                      */
  641.                     $list = array();
  642.                     break;
  643.                 }
  644.             }
  645.         }
  646.  
  647.         return $list;
  648.     }
  649.  
  650.     /**
  651.      * Parse an Array of Files
  652.      *
  653.      * You can parse an array of Files or Strings, to parse
  654.      * strings, $options['is_string'] must be set to true
  655.      *
  656.      * @param array $dataSource Array of file &| directory names or code strings
  657.      * @param array $options    Parser options (see parseData() method for details)
  658.      *
  659.      * @access private
  660.      * @return array or false on error
  661.      * @since  version 0.7.0 (2004-03-09)
  662.      * @see    parseData()
  663.      */
  664.     function _parseArray($dataSource$options = array())
  665.     {
  666.         // Each data source have been checked before (see _validateDataSource() )
  667.         if (is_file($dataSource[0])) {
  668.             $parseData $this->_parseDir($dataSource$options);
  669.         else {
  670.             $parseData $this->_parseString($dataSource$options);
  671.         }
  672.  
  673.         return $parseData;
  674.     }
  675.  
  676.     /**
  677.      * Parse a string
  678.      *
  679.      * Parse a string for its compatibility info.
  680.      *
  681.      * @param array $strings PHP Code to parse
  682.      * @param array $options Parser options (see parseData() method for details)
  683.      *
  684.      * @access private
  685.      * @return array or false on error
  686.      * @since  version 0.7.0 (2004-03-09)
  687.      * @see    parseData()
  688.      */
  689.     function _parseString($strings$options = array())
  690.     {
  691.         $results $this->_parseElements($strings$options);
  692.         return $results;
  693.     }
  694.  
  695.     /**
  696.      * Parse a single file
  697.      *
  698.      * Parse a single file for its compatibility info.
  699.      *
  700.      * @param string $file    File to parse
  701.      * @param array  $options Parser options (see parseData() method for details)
  702.      *
  703.      * @access private
  704.      * @return array or false on error
  705.      * @since  version 0.7.0 (2004-03-09)
  706.      * @see    parseData()
  707.      */
  708.     function _parseFile($file$options = array())
  709.     {
  710.         $results $this->_parseElements($file$options);
  711.         return $results;
  712.     }
  713.  
  714.     /**
  715.      * Parse a directory
  716.      *
  717.      * Parse a directory recursively for its compatibility info
  718.      *
  719.      * @param array $files   Files list of folder to parse
  720.      * @param array $options Parser options (see parseData() method for details)
  721.      *
  722.      * @access private
  723.      * @return array or false on error
  724.      * @since  version 0.8.0 (2004-04-22)
  725.      * @see    parseData()
  726.      */
  727.     function _parseDir($files$options = array())
  728.     {
  729.         $results $this->_parseElements($files$options);
  730.         return $results;
  731.     }
  732.  
  733.     /**
  734.      * Parse a list of elements
  735.      *
  736.      * Parse a list of directory|file elements, or chunk of code (strings)
  737.      *
  738.      * @param array $elements Array of file &| directory names or code strings
  739.      * @param array $options  Parser options (see parseData() method for details)
  740.      *
  741.      * @access private
  742.      * @return array 
  743.      * @since  version 1.8.0b3 (2008-06-07)
  744.      * @see    _parseString(), _parseDir()
  745.      */
  746.     function _parseElements($elements$options = array())
  747.     {
  748.         $files_parsed       = array();
  749.         $latest_version     $this->latest_version;
  750.         $earliest_version   $this->earliest_version;
  751.         $all_functions      = array();
  752.         $functions          = array();
  753.         $extensions         = array();
  754.         $constants          = array();
  755.         $tokens             = array();
  756.         $ignored_functions  = array();
  757.         $ignored_extensions = array();
  758.         $ignored_constants  = array();
  759.         $function_exists    = array();
  760.         $extension_loaded   = array();
  761.         $defined            = array();
  762.         $cond_code          = 0;
  763.  
  764.         foreach ($elements as $p => $element{
  765.             $index $p + 1;
  766.             if (is_file($element)) {
  767.                 if (in_array($element$options['ignore_files'])) {
  768.                     $this->ignored_files[$element;
  769.                     continue;
  770.                 }
  771.                 $eventInfo
  772.                     = array('filename' => $element'fileindex' => $index);
  773.                 $this->notifyListeners(PHP_COMPATINFO_EVENT_FILESTARTED$eventInfo);
  774.  
  775.                 $tokens_list          $this->_tokenize($element);
  776.                 $kfile                $element;
  777.                 $files_parsed[$kfile$this->_parseTokens($tokens_list$options);
  778.  
  779.                 $this->notifyListeners(PHP_COMPATINFO_EVENT_FILEFINISHED);
  780.             else {
  781.                 $eventInfo
  782.                     = array('stringdata' => $element'stringindex' => $index);
  783.                 $this->notifyListeners(PHP_COMPATINFO_EVENT_CODESTARTED$eventInfo);
  784.  
  785.                 $tokens_list          $this->_tokenize($elementtrue);
  786.                 $kfile                'string_' $index;
  787.                 $files_parsed[$kfile$this->_parseTokens($tokens_list$options);
  788.  
  789.                 $this->notifyListeners(PHP_COMPATINFO_EVENT_CODEFINISHED);
  790.             }
  791.         }
  792.  
  793.         foreach ($files_parsed as $fn => $file{
  794.             $cmp version_compare($latest_version$file['version']);
  795.             if ($cmp === -1{
  796.                 $latest_version $file['version'];
  797.             }
  798.             if ($file['max_version'!= ''{
  799.                 $cmp version_compare($earliest_version$file['max_version']);
  800.                 if ($earliest_version == '' || $cmp === 1{
  801.                     $earliest_version $file['max_version'];
  802.                 }
  803.             }
  804.             foreach ($file['functions'as $func{
  805.                 if (!in_array($func$functions)) {
  806.                     $functions[$func;
  807.                 }
  808.             }
  809.             foreach ($file['extensions'as $ext{
  810.                 if (!in_array($ext$extensions)) {
  811.                     $extensions[$ext;
  812.                 }
  813.             }
  814.             foreach ($file['constants'as $const{
  815.                 if (!in_array($const$constants)) {
  816.                     $constants[$const;
  817.                 }
  818.             }
  819.             foreach ($file['tokens'as $token{
  820.                 if (!in_array($token$tokens)) {
  821.                     $tokens[$token;
  822.                 }
  823.             }
  824.             foreach ($file['ignored_functions'as $if{
  825.                 if (!in_array($if$ignored_functions)) {
  826.                     $ignored_functions[$if;
  827.                 }
  828.             }
  829.             foreach ($file['ignored_extensions'as $ie{
  830.                 if (!in_array($ie$ignored_extensions)) {
  831.                     $ignored_extensions[$ie;
  832.                 }
  833.             }
  834.             foreach ($file['ignored_constants'as $ic{
  835.                 if (!in_array($ic$ignored_constants)) {
  836.                     $ignored_constants[$ic;
  837.                 }
  838.             }
  839.             foreach ($file['cond_code'][1][0as $ccf{
  840.                 if (!in_array($ccf$function_exists)) {
  841.                     $function_exists[$ccf;
  842.                 }
  843.             }
  844.             foreach ($file['cond_code'][1][1as $cce{
  845.                 if (!in_array($cce$extension_loaded)) {
  846.                     $extension_loaded[$cce;
  847.                 }
  848.             }
  849.             foreach ($file['cond_code'][1][2as $ccc{
  850.                 if (!in_array($ccc$defined)) {
  851.                     $defined[$ccc;
  852.                 }
  853.             }
  854.             if ($options['debug'=== false{
  855.                 unset($files_parsed[$fn]['cond_code'][1]);
  856.             else {
  857.                 unset($file['ignored_functions']);
  858.                 unset($file['ignored_extensions']);
  859.                 unset($file['ignored_constants']);
  860.                 unset($file['max_version']);
  861.                 unset($file['version']);
  862.                 unset($file['functions']);
  863.                 unset($file['extensions']);
  864.                 unset($file['constants']);
  865.                 unset($file['tokens']);
  866.                 unset($file['cond_code']);
  867.  
  868.                 foreach ($file as $version => $functions{
  869.                     // extra information available only when debug mode is on
  870.                     if (isset($all_functions[$version])) {
  871.                         foreach ($functions as $func{
  872.                             $k array_search($func$all_functions[$version]);
  873.                             if ($k === false{
  874.                                 $all_functions[$version][$func;
  875.                             }
  876.                         }
  877.                     else {
  878.                         $all_functions[$version$functions;
  879.                     }
  880.                 }
  881.             }
  882.         }
  883.  
  884.         if (count($files_parsed== 0{
  885.             return false;
  886.         }
  887.  
  888.         if (count($function_exists> 0{
  889.             $cond_code += 1;
  890.         }
  891.         if (count($extension_loaded> 0{
  892.             $cond_code += 2;
  893.         }
  894.         if (count($defined> 0{
  895.             $cond_code += 4;
  896.         }
  897.         if ($options['debug'=== false{
  898.             $cond_code = array($cond_code);
  899.         else {
  900.             $cond_code = array($cond_codearray($function_exists,
  901.                                                  $extension_loaded,
  902.                                                  $defined));
  903.         }
  904.  
  905.         sort($ignored_functions);
  906.         sort($ignored_extensions);
  907.         sort($ignored_constants);
  908.         sort($functions);
  909.         sort($extensions);
  910.         sort($constants);
  911.         sort($tokens);
  912.         $main_info = array('ignored_files'      => $this->getIgnoredFiles(),
  913.                            'ignored_functions'  => $ignored_functions,
  914.                            'ignored_extensions' => $ignored_extensions,
  915.                            'ignored_constants'  => $ignored_constants,
  916.                            'max_version'   => $earliest_version,
  917.                            'version'       => $latest_version,
  918.                            'functions'     => $functions,
  919.                            'extensions'    => $extensions,
  920.                            'constants'     => $constants,
  921.                            'tokens'        => $tokens,
  922.                            'cond_code'     => $cond_code);
  923.  
  924.         if (count($files_parsed== 1{
  925.             if ($options['debug'=== false{
  926.                 $parseData $main_info;
  927.             else {
  928.                 $main_info = array('ignored_files' => $this->getIgnoredFiles());
  929.                 $parseData array_merge($main_info,
  930.                                          $files_parsed[$kfile]$all_functions);
  931.             }
  932.         else {
  933.             if ($options['debug'=== false{
  934.                 $parseData array_merge($main_info$files_parsed);
  935.             else {
  936.                 $parseData array_merge($main_info$all_functions$files_parsed);
  937.             }
  938.         }
  939.  
  940.         $this->notifyListeners(PHP_COMPATINFO_EVENT_FILEFINISHED$parseData);
  941.         return $parseData;
  942.     }
  943.  
  944.     /**
  945.      * Token a file or string
  946.      *
  947.      * @param string  $input     Filename or PHP code
  948.      * @param boolean $is_string Whether or note the input is a string
  949.      * @param boolean $debug     add token names for human read
  950.      *
  951.      * @access private
  952.      * @return array 
  953.      * @since  version 0.7.0 (2004-03-09)
  954.      */
  955.     function _tokenize($input$is_string = false$debug = false)
  956.     {
  957.         if ($is_string === false{
  958.             $input file_get_contents($inputtrue);
  959.         }
  960.         $tokens token_get_all($input);
  961.  
  962.         if ($debug === true{
  963.             $r = array();
  964.             foreach ($tokens as $token{
  965.                 if (is_array($token)) {
  966.                     $token[token_name($token[0]);
  967.                 else {
  968.                     $token $token[0];
  969.                 }
  970.                 $r[$token;
  971.             }
  972.         else {
  973.             $r $tokens;
  974.         }
  975.         return $r;
  976.     }
  977.  
  978.     /**
  979.      * Parse the given Tokens
  980.      *
  981.      * The tokens are those returned by token_get_all() which is nicely
  982.      * wrapped in PHP_CompatInfo::_tokenize
  983.      *
  984.      * @param array   $tokens  Array of PHP Tokens
  985.      * @param boolean $options Show Extra Output
  986.      *
  987.      * @access private
  988.      * @return array 
  989.      * @since  version 0.7.0 (2004-03-09)
  990.      */
  991.     function _parseTokens($tokens$options)
  992.     {
  993.         static $akeys;
  994.  
  995.         $functions          = array();
  996.         $functions_version  = array();
  997.         $latest_version     $this->latest_version;
  998.         $earliest_version   $this->earliest_version;
  999.         $extensions         = array();
  1000.         $constants          = array();
  1001.         $constant_names     = array();
  1002.         $token_names        = array();
  1003.         $udf                = array();
  1004.         $ignore_functions   = array();
  1005.         $ignored_functions  = array();
  1006.         $ignore_extensions  = array();
  1007.         $ignored_extensions = array();
  1008.         $ignore_constants   = array();
  1009.         $ignored_constants  = array();
  1010.         $function_exists    = array();
  1011.         $extension_loaded   = array();
  1012.         $defined            = array();
  1013.         $cond_code          = 0;
  1014.  
  1015.         if (isset($options['ignore_constants'])) {
  1016.             $options['ignore_constants']
  1017.                 = array_map('strtoupper'$options['ignore_constants']);
  1018.         else {
  1019.             $options['ignore_constants'= array();
  1020.         }
  1021.         if (isset($options['ignore_extensions'])) {
  1022.             $options['ignore_extensions']
  1023.                 = array_map('strtolower'$options['ignore_extensions']);
  1024.         else {
  1025.             $options['ignore_extensions'= array();
  1026.         }
  1027.         if (isset($options['ignore_versions'][0])) {
  1028.             $min_ver $options['ignore_versions'][0];
  1029.         else {
  1030.             $min_ver = false;
  1031.         }
  1032.         if (isset($options['ignore_versions'][1])) {
  1033.             $max_ver $options['ignore_versions'][1];
  1034.         else {
  1035.             $max_ver = false;
  1036.         }
  1037.  
  1038.         if (isset($options['ignore_functions_match'])) {
  1039.             list($ifm_compare$ifm_patterns$options['ignore_functions_match'];
  1040.         else {
  1041.             $ifm_compare = false;
  1042.         }
  1043.         if (isset($options['ignore_extensions_match'])) {
  1044.             list($iem_compare$iem_patterns$options['ignore_extensions_match'];
  1045.         else {
  1046.             $iem_compare = false;
  1047.         }
  1048.         if (isset($options['ignore_constants_match'])) {
  1049.             list($icm_compare$icm_patterns$options['ignore_constants_match'];
  1050.         else {
  1051.             $icm_compare = false;
  1052.         }
  1053.  
  1054.         $token_count sizeof($tokens);
  1055.         $i           = 0;
  1056.         $found_class = false;
  1057.         while ($i $token_count{
  1058.             if ($this->_isToken($tokens[$i]'T_FUNCTION')) {
  1059.                 $found_func = false;
  1060.             else {
  1061.                 $found_func = true;
  1062.             }
  1063.             while ($found_func == false{
  1064.                 $i += 1;
  1065.                 if ($this->_isToken($tokens[$i]'T_STRING')) {
  1066.                     $found_func = true;
  1067.                     $func       $tokens[$i][1];
  1068.                     if ($found_class === false
  1069.                         || in_array($func$function_exists)) {
  1070.                         $udf[$func;
  1071.                     }
  1072.                 }
  1073.             }
  1074.  
  1075.             // Try to detect PHP method chaining implementation
  1076.             if ($this->_isToken($tokens[$i]'T_VARIABLE')
  1077.                 && $this->_isToken($tokens[$i+1]'T_OBJECT_OPERATOR')
  1078.                 && $this->_isToken($tokens[$i+2]'T_STRING')
  1079.                 && $this->_isToken($tokens[$i+3]'(')) {
  1080.  
  1081.                 $i                   += 3;
  1082.                 $php5_method_chaining = false;
  1083.                 while ((!is_array($tokens[$i]&& $tokens[$i== ';'=== false{
  1084.                     $i += 1;
  1085.                     if ((($this->_isToken($tokens[$i]')'))
  1086.                         || ($this->_isToken($tokens[$i]'T_WHITESPACE')))
  1087.                         && $this->_isToken($tokens[$i+1]'T_OBJECT_OPERATOR')) {
  1088.  
  1089.                         $php5_method_chaining = true;
  1090.                     }
  1091.                 }
  1092.             }
  1093.  
  1094.             // Compare "ignore_functions_match" pre-condition
  1095.             if (is_string($ifm_compare)) {
  1096.                 if (strcasecmp('preg_match'$ifm_compare!= 0{
  1097.                     // Try to catch function_exists() condition
  1098.                     if ($this->_isToken($tokens[$i]'T_STRING')
  1099.                         && (strcasecmp($tokens[$i][1]$ifm_compare== 0)) {
  1100.  
  1101.                         while ((!$this->_isToken($tokens[$i],
  1102.                                                  'T_CONSTANT_ENCAPSED_STRING'))) {
  1103.                             $i += 1;
  1104.                         }
  1105.                         $func trim($tokens[$i][1]"'");
  1106.  
  1107.                         /**
  1108.                          * try if function_exists()
  1109.                          * match one or more pattern condition
  1110.                          */
  1111.                         foreach ($ifm_patterns as $pattern{
  1112.                             if (preg_match($pattern$func=== 1{
  1113.                                 $ignore_functions[$func;
  1114.                             }
  1115.                         }
  1116.                     }
  1117.                 }
  1118.             }
  1119.  
  1120.             // Compare "ignore_extensions_match" pre-condition
  1121.             if (is_string($iem_compare)) {
  1122.                 if (strcasecmp('preg_match'$iem_compare!= 0{
  1123.                     // Try to catch extension_loaded() condition
  1124.                     if ($this->_isToken($tokens[$i]'T_STRING')
  1125.                         && (strcasecmp($tokens[$i][1]$iem_compare== 0)) {
  1126.  
  1127.                         while ((!$this->_isToken($tokens[$i],
  1128.                                                  'T_CONSTANT_ENCAPSED_STRING'))) {
  1129.                             $i += 1;
  1130.                         }
  1131.                         $ext trim($tokens[$i][1]"'");
  1132.  
  1133.                         /**
  1134.                          * try if extension_loaded()
  1135.                          * match one or more pattern condition
  1136.                          */
  1137.                         foreach ($iem_patterns as $pattern{
  1138.                             if (preg_match($pattern$ext=== 1{
  1139.                                 $ignore_extensions[$ext;
  1140.                             }
  1141.                         }
  1142.                     }
  1143.                 }
  1144.             }
  1145.  
  1146.             // Compare "ignore_constants_match" pre-condition
  1147.             if (is_string($icm_compare)) {
  1148.                 if (strcasecmp('preg_match'$icm_compare!= 0{
  1149.                     // Try to catch defined() condition
  1150.                     if ($this->_isToken($tokens[$i]'T_STRING')
  1151.                         && (strcasecmp($tokens[$i][1]$icm_compare== 0)) {
  1152.  
  1153.                         while ((!$this->_isToken($tokens[$i],
  1154.                                                  'T_CONSTANT_ENCAPSED_STRING'))) {
  1155.                             $i += 1;
  1156.                         }
  1157.                         $cst trim($tokens[$i][1]"'");
  1158.  
  1159.                         /**
  1160.                          * try if defined()
  1161.                          * match one or more pattern condition
  1162.                          */
  1163.                         foreach ($icm_patterns as $pattern{
  1164.                             if (preg_match($pattern$cst=== 1{
  1165.                                 $ignore_constants[$cst;
  1166.                             }
  1167.                         }
  1168.                     }
  1169.                 }
  1170.             }
  1171.  
  1172.             if ($this->_isToken($tokens[$i]'T_STRING')
  1173.                 && (isset($tokens[$i+1]))
  1174.                 && $this->_isToken($tokens[$i+1]'(')) {
  1175.  
  1176.                 $is_function = false;
  1177.  
  1178.                 if (isset($tokens[$i-1])
  1179.                     && !$this->_isToken($tokens[$i-1]'T_DOUBLE_COLON')
  1180.                     && !$this->_isToken($tokens[$i-1]'T_OBJECT_OPERATOR')) {
  1181.  
  1182.                     if (isset($tokens[$i-2])
  1183.                         && $this->_isToken($tokens[$i-2]'T_FUNCTION')) {
  1184.                         // its a function declaration
  1185.                     else {
  1186.                         $is_function = true;
  1187.                     }
  1188.                 }
  1189.                 if ($is_function == true || !is_array($tokens[$i-1])) {
  1190.                     $functions[strtolower($tokens[$i][1]);
  1191.                 }
  1192.             }
  1193.  
  1194.             // try to detect condition function_exists()
  1195.             if ($this->_isToken($tokens[$i]'T_STRING')
  1196.                 && (strcasecmp($tokens[$i][1]'function_exists'== 0)) {
  1197.  
  1198.                 $j $i;
  1199.                 while ((!$this->_isToken($tokens[$j]')'))) {
  1200.                     if ($this->_isToken($tokens[$j]'T_CONSTANT_ENCAPSED_STRING')) {
  1201.                         $t_string          $tokens[$j][1];
  1202.                         $t_string          trim($t_string"'");
  1203.                         $t_string          trim($t_string'"');
  1204.                         $function_exists[$t_string;
  1205.                     }
  1206.                     $j++;
  1207.                 }
  1208.             }
  1209.             // try to detect condition extension_loaded()
  1210.             if ($this->_isToken($tokens[$i]'T_STRING')
  1211.                 && (strcasecmp($tokens[$i][1]'extension_loaded'== 0)) {
  1212.  
  1213.                 $j $i;
  1214.                 while ((!$this->_isToken($tokens[$j]')'))) {
  1215.                     if ($this->_isToken($tokens[$j]'T_CONSTANT_ENCAPSED_STRING')) {
  1216.                         $t_string           $tokens[$j][1];
  1217.                         $t_string           trim($t_string"'");
  1218.                         $t_string           trim($t_string'"');
  1219.                         $extension_loaded[$t_string;
  1220.                     }
  1221.                     $j++;
  1222.                 }
  1223.             }
  1224.             // try to detect condition defined()
  1225.             if ($this->_isToken($tokens[$i]'T_STRING')
  1226.                 && (strcasecmp($tokens[$i][1]'defined'== 0)) {
  1227.  
  1228.                 $j $i;
  1229.                 while ((!$this->_isToken($tokens[$j]')'))) {
  1230.                     if ($this->_isToken($tokens[$j]'T_CONSTANT_ENCAPSED_STRING')) {
  1231.                         $t_string  $tokens[$j][1];
  1232.                         $t_string  trim($t_string"'");
  1233.                         $t_string  trim($t_string'"');
  1234.                         $defined[$t_string;
  1235.                     }
  1236.                     $j++;
  1237.                 }
  1238.             }
  1239.  
  1240.             // try to detect beginning of a class
  1241.             if ($this->_isToken($tokens[$i]'T_CLASS')) {
  1242.                 $found_class = true;
  1243.             }
  1244.  
  1245.             if (is_array($tokens[$i])) {
  1246.                 if (!isset($akeys)) {
  1247.                     // build contents one time only (static variable)
  1248.                     $akeys array_keys($GLOBALS['_PHP_COMPATINFO_CONST']);
  1249.                 }
  1250.                 $const strtoupper($tokens[$i][1]);
  1251.                 $found array_search($const$akeys);
  1252.                 if ($found !== false{
  1253.                     if ($this->_isToken($tokens[$i]'T_ENCAPSED_AND_WHITESPACE')) {
  1254.                         // PHP 5 constant tokens found into a string
  1255.                     else {
  1256.                         // Compare "ignore_constants_match" free condition
  1257.                         $icm_preg_match = false;
  1258.                         if (is_string($icm_compare)) {
  1259.                             if (strcasecmp('preg_match'$icm_compare== 0{
  1260.                                 /**
  1261.                                  * try if preg_match()
  1262.                                  * match one or more pattern condition
  1263.                                  */
  1264.                                 foreach ($icm_patterns as $pattern{
  1265.                                     if (preg_match($pattern$const=== 1{
  1266.                                         $icm_preg_match = true;
  1267.                                         break;
  1268.                                     }
  1269.                                 }
  1270.                             }
  1271.                         }
  1272.  
  1273.                         $init $GLOBALS['_PHP_COMPATINFO_CONST'][$const]['init'];
  1274.                         if (!PHP_CompatInfo_Parser::_ignore($init,
  1275.                                                             $min_ver$max_ver)) {
  1276.                             $constants[$const;
  1277.                             if (in_array($const$ignore_constants)
  1278.                                 || in_array($const$options['ignore_constants'])
  1279.                                 || $icm_preg_match{
  1280.                                 $ignored_constants[$const;
  1281.                             else {
  1282.                                 $latest_version $init;
  1283.                             }
  1284.                         }
  1285.                     }
  1286.                 }
  1287.             }
  1288.             $i += 1;
  1289.         }
  1290.  
  1291.         $functions array_unique($functions);
  1292.         if (isset($options['ignore_functions'])) {
  1293.             $options['ignore_functions']
  1294.                 = array_map('strtolower'$options['ignore_functions']);
  1295.         else {
  1296.             $options['ignore_functions'= array();
  1297.         }
  1298.         if (count($ignore_functions> 0{
  1299.             $ignore_functions array_map('strtolower'$ignore_functions);
  1300.             $options['ignore_functions']
  1301.                 = array_merge($options['ignore_functions']$ignore_functions);
  1302.             $options['ignore_functions']
  1303.                 = array_unique($options['ignore_functions']);
  1304.         }
  1305.         if (count($ignore_extensions> 0{
  1306.             $ignore_extensions array_map('strtolower'$ignore_extensions);
  1307.             $options['ignore_extensions']
  1308.                 = array_merge($options['ignore_extensions']$ignore_extensions);
  1309.             $options['ignore_extensions']
  1310.                 = array_unique($options['ignore_extensions']);
  1311.         }
  1312.  
  1313.         foreach ($functions as $name{
  1314.             if (!isset($GLOBALS['_PHP_COMPATINFO_FUNCS'][$name])) {
  1315.                 continue;  // skip this unknown function
  1316.             }
  1317.             $func $GLOBALS['_PHP_COMPATINFO_FUNCS'][$name];
  1318.  
  1319.             // retrieve if available the extension name
  1320.             if ((isset($func['ext']))
  1321.                 && ($func['ext'!= 'ext_standard')
  1322.                 && ($func['ext'!= 'zend')) {
  1323.                 if ($func['pecl'=== false{
  1324.                     $extension substr($func['ext']4);
  1325.                     if ($extension{0== '_'{
  1326.                         $extension $func['ext'];
  1327.                     }
  1328.                 else {
  1329.                     $extension $func['ext'];
  1330.                 }
  1331.             else {
  1332.                 $extension = false;
  1333.             }
  1334.  
  1335.             // Compare "ignore_functions_match" free condition
  1336.             $ifm_preg_match = false;
  1337.             if (is_string($ifm_compare)) {
  1338.                 if (strcasecmp('preg_match'$ifm_compare== 0{
  1339.                     /**
  1340.                      * try if preg_match()
  1341.                      * match one or more pattern condition
  1342.                      */
  1343.                     foreach ($ifm_patterns as $pattern{
  1344.                         if (preg_match($pattern$name=== 1{
  1345.                             $ifm_preg_match = true;
  1346.                             break;
  1347.                         }
  1348.                     }
  1349.                 }
  1350.             }
  1351.  
  1352.             if ((!in_array($name$udf))
  1353.                 && (!in_array($name$options['ignore_functions']))
  1354.                 && ($ifm_preg_match === false)) {
  1355.  
  1356.                 if ($extension && !in_array($extension$extensions)) {
  1357.                     $extensions[substr($func['ext']04== 'ext_'
  1358.                         ? $extension $func['ext'];
  1359.                 }
  1360.  
  1361.                 // Compare "ignore_extensions_match" free condition
  1362.                 $iem_preg_match = false;
  1363.                 if (is_string($iem_compare)) {
  1364.                     if (strcasecmp('preg_match'$iem_compare== 0{
  1365.                         /**
  1366.                          * try if preg_match()
  1367.                          * match one or more pattern condition
  1368.                          */
  1369.                         foreach ($iem_patterns as $pattern{
  1370.                             if (preg_match($pattern$extension=== 1{
  1371.                                 $iem_preg_match = true;
  1372.                                 break;
  1373.                             }
  1374.                         }
  1375.                     }
  1376.                 }
  1377.  
  1378.                 if ($extension
  1379.                     && (in_array($extension$options['ignore_extensions'])
  1380.                         || $iem_preg_match)) {
  1381.                     if (!in_array($extension$ignored_extensions)) {
  1382.                         // extension is ignored (only once)
  1383.                         $ignored_extensions[$extension;
  1384.                     }
  1385.                     // all extension functions are also ignored
  1386.                     $ignored_functions[$name;
  1387.                     continue;  // skip this extension function
  1388.                 }
  1389.  
  1390.                 if (PHP_CompatInfo_Parser::_ignore($func['init'],
  1391.                                                    $min_ver$max_ver)) {
  1392.                     continue;  // skip this function version
  1393.                 }
  1394.  
  1395.                 if ($options['debug'== true{
  1396.                     $functions_version[$func['init']][= array(
  1397.                         'function' => $name,
  1398.                         'extension' => substr($func['ext']04== 'ext_'
  1399.                             ? $extension $func['ext'],
  1400.                         'pecl' => $func['pecl']
  1401.                         );
  1402.                 }
  1403.                 if ($extension === false
  1404.                     || (isset($func['pecl']&& $func['pecl'=== false) ) {
  1405.                     $cmp version_compare($latest_version$func['init']);
  1406.                     if ($cmp === -1{
  1407.                         $latest_version $func['init'];
  1408.                     }
  1409.                     if (array_key_exists('end'$func)) {
  1410.                         $cmp version_compare($earliest_version$func['end']);
  1411.                         if ($earliest_version == '' || $cmp === 1{
  1412.                             $earliest_version $func['end'];
  1413.                         }
  1414.                     }
  1415.                 }
  1416.  
  1417.             else {
  1418.                 // function is ignored
  1419.                 $ignored_functions[$name;
  1420.             }
  1421.         }
  1422.  
  1423.         $ignored_constants array_unique($ignored_constants);
  1424.         $constants         array_unique($constants);
  1425.         foreach ($constants as $constant{
  1426.             $const $GLOBALS['_PHP_COMPATINFO_CONST'][$constant];
  1427.             if (PHP_CompatInfo_Parser::_ignore($const['init']$min_ver$max_ver)) {
  1428.                 continue;  // skip this constant version
  1429.             }
  1430.             if (!in_array($constant$ignored_constants)) {
  1431.                 $cmp version_compare($latest_version$const['init']);
  1432.                 if ($cmp === -1{
  1433.                     $latest_version $const['init'];
  1434.                 }
  1435.                 if (array_key_exists('end'$const)) {
  1436.                     $cmp version_compare($earliest_version$const['end']);
  1437.                     if ($earliest_version == '' || $cmp === 1{
  1438.                         $earliest_version $const['end'];
  1439.                     }
  1440.                 }
  1441.             }
  1442.             if (!in_array($const['name']$constant_names)) {
  1443.                 // split PHP5 tokens and pure PHP constants
  1444.                 if ($const['name'== strtolower($const['name'])) {
  1445.                     $token_names[$const['name'];
  1446.                 else {
  1447.                     $constant_names[$const['name'];
  1448.                 }
  1449.             }
  1450.         }
  1451.  
  1452.         if (isset($php5_method_chaining)
  1453.             && $php5_method_chaining === true
  1454.             && version_compare($latest_version'5.0.0'< 0{
  1455.             // when PHP Method chaining is detected, only available for PHP 5
  1456.             $latest_version '5.0.0';
  1457.         }
  1458.  
  1459.         ksort($functions_version);
  1460.  
  1461.         if (count($function_exists> 0{
  1462.             $function_exists array_unique($function_exists);
  1463.             $cond_code      += 1;
  1464.         }
  1465.         if (count($extension_loaded> 0{
  1466.             $extension_loaded array_unique($extension_loaded);
  1467.             $cond_code       += 2;
  1468.         }
  1469.         if (count($defined> 0{
  1470.             $defined    array_unique($defined);
  1471.             $cond_code += 4;
  1472.         }
  1473.         $cond_code = array($cond_codearray($function_exists,
  1474.                                              $extension_loaded,
  1475.                                              $defined));
  1476.  
  1477.         sort($ignored_functions);
  1478.         sort($ignored_extensions);
  1479.         sort($ignored_constants);
  1480.         sort($functions);
  1481.         sort($extensions);
  1482.         sort($constant_names);
  1483.         sort($token_names);
  1484.         $main_info = array('ignored_functions'  => $ignored_functions,
  1485.                            'ignored_extensions' => $ignored_extensions,
  1486.                            'ignored_constants'  => $ignored_constants,
  1487.                            'max_version' => $earliest_version,
  1488.                            'version'     => $latest_version,
  1489.                            'functions'   => $functions,
  1490.                            'extensions'  => $extensions,
  1491.                            'constants'   => $constant_names,
  1492.                            'tokens'      => $token_names,
  1493.                            'cond_code'   => $cond_code);
  1494.  
  1495.         $functions_version array_merge($main_info$functions_version);
  1496.         return $functions_version;
  1497.     }
  1498.  
  1499.     /**
  1500.      * Checks if function which has $init version should be keep
  1501.      * or ignore (version is between $min_ver and $max_ver).
  1502.      *
  1503.      * @param string $init    version of current function
  1504.      * @param string $min_ver minimum version of function to ignore
  1505.      * @param string $max_ver maximum version of function to ignore
  1506.      *
  1507.      * @access private
  1508.      * @return boolean True to ignore function/constant, false otherwise
  1509.      * @since  version 1.4.0 (2006-09-27)
  1510.      * @static
  1511.      */
  1512.     function _ignore($init$min_ver$max_ver)
  1513.     {
  1514.         if ($min_ver{
  1515.             $cmp version_compare($init$min_ver);
  1516.             if ($max_ver && $cmp >= 0{
  1517.                 $cmp version_compare($init$max_ver);
  1518.                 if ($cmp < 1{
  1519.                     return true;
  1520.                 }
  1521.             elseif ($cmp === 0{
  1522.                 return true;
  1523.             }
  1524.         }
  1525.         return false;
  1526.     }
  1527.  
  1528.     /**
  1529.      * Checks if the given token is of this symbolic name
  1530.      *
  1531.      * @param mixed  $token    Single PHP token to test
  1532.      * @param string $symbolic Symbolic name of the given token
  1533.      *
  1534.      * @access private
  1535.      * @return bool 
  1536.      * @since  version 1.7.0b4 (2008-04-03)
  1537.      */
  1538.     function _isToken($token$symbolic)
  1539.     {
  1540.         if (is_array($token)) {
  1541.             $t token_name($token[0]);
  1542.         else {
  1543.             $t $token;
  1544.         }
  1545.         return ($t == $symbolic);
  1546.     }
  1547.  
  1548.     /**
  1549.      * Computes the difference of arrays
  1550.      *
  1551.      * Computes the difference of arrays and returns result without original keys
  1552.      *
  1553.      * @param array $array1 The array to compare from
  1554.      * @param array $array2 The array to compare against
  1555.      *
  1556.      * @access private
  1557.      * @static
  1558.      * @link   http://www.php.net/manual/en/function.array-diff.php#82297
  1559.      * @return array 
  1560.      * @since  version 1.8.0b2 (2008-06-03)
  1561.      */
  1562.     function _arrayDiff($array1$array2)
  1563.     {
  1564.         // This wrapper for array_diff rekeys the array returned
  1565.         $valid_array array_diff($array1$array2);
  1566.  
  1567.         // reinstantiate $array1 variable
  1568.         $array1 = array();
  1569.  
  1570.         // loop through the validated array and move elements to $array1
  1571.         // this is necessary because the array_diff function
  1572.         // returns arrays that retain their original keys
  1573.         foreach ($valid_array as $valid{
  1574.             $array1[$valid;
  1575.         }
  1576.         return $array1;
  1577.     }
  1578. }
  1579. ?>

Documentation generated on Fri, 01 Aug 2008 11:30:30 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.