Apache Zeta Components Manual :: File Source for file.php

Source for file file.php

Documentation is available at file.php

  1. <?php
  2. /**
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements.  See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership.  The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License.  You may obtain a copy of the License at
  11.  * 
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  * 
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  *
  21.  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  22.  * @version //autogentag//
  23.  * @filesource
  24.  * @package Base
  25.  */
  26.  
  27. /**
  28.  * Provides a selection of static independent methods to provide functionality
  29.  * for file and file system handling.
  30.  *
  31.  * This example shows how to use the findRecursive method:
  32.  * <code>
  33.  * <?php
  34.  * // lists all the files under /etc (including subdirectories) that end in
  35.  * // .conf
  36.  * $confFiles = ezcBaseFile::findRecursive( "/etc", array( '@\.conf$@' ) );
  37.  *
  38.  * // lists all autoload files in the components source tree and excludes the
  39.  * // ones in the autoload subdirectory. Statistics are returned in the $stats
  40.  * // variable which is passed by reference.
  41.  * $files = ezcBaseFile::findRecursive(
  42.  *     "/dat/dev/ezcomponents",
  43.  *     array( '@src/.*_autoload.php$@' ),
  44.  *     array( '@/autoload/@' ),
  45.  *     $stats
  46.  * );
  47.  *
  48.  * // lists all binaries in /bin except the ones starting with a "g"
  49.  * $data = ezcBaseFile::findRecursive( "/bin", array(), array( '@^/bin/g@' ) );
  50.  * ?>
  51.  * </code>
  52.  *
  53.  * @package Base
  54.  * @version //autogentag//
  55.  * @mainclass
  56.  */
  57. {
  58.     /**
  59.      * This is the callback used by findRecursive to collect data.
  60.      *
  61.      * This callback method works together with walkRecursive() and is called
  62.      * for every file/and or directory. The $context is a callback specific
  63.      * container in which data can be stored and shared between the different
  64.      * calls to the callback function. The walkRecursive() function also passes
  65.      * in the full absolute directory in $sourceDir, the filename in $fileName
  66.      * and file information (such as size, modes, types) as an array as
  67.      * returned by PHP's stat() in the $fileInfo parameter.
  68.      *
  69.      * @param ezcBaseFileFindContext $context 
  70.      * @param string $sourceDir 
  71.      * @param string $fileName 
  72.      * @param array(stat) $fileInfo 
  73.      */
  74.     static protected function findRecursiveCallbackezcBaseFileFindContext $context$sourceDir$fileName$fileInfo )
  75.     {
  76.         // ignore if we have a directory
  77.         if $fileInfo['mode'0x4000 )
  78.         {
  79.             return;
  80.         }
  81.  
  82.         // update the statistics
  83.         $context->elements[$sourceDir DIRECTORY_SEPARATOR $fileName;
  84.         $context->count++;
  85.         $context->size += $fileInfo['size'];
  86.     }
  87.  
  88.     /**
  89.      * Walks files and directories recursively on a file system
  90.      *
  91.      * This method walks over a directory and calls a callback from every file
  92.      * and directory it finds. You can use $includeFilters to include only
  93.      * specific files, and $excludeFilters to exclude certain files from being
  94.      * returned. The function will always go into subdirectories even if the
  95.      * entry would not have passed the filters.
  96.      *
  97.      * The callback is passed in the $callback parameter, and the
  98.      * $callbackContext will be send to the callback function/method as
  99.      * parameter so that you can store data in there that persists with all the
  100.      * calls and recursive calls to this method. It's up to the callback method
  101.      * to do something useful with this. The callback function's parameters are
  102.      * in order:
  103.      *
  104.      * <ul>
  105.      * <li>ezcBaseFileFindContext $context</li>
  106.      * <li>string $sourceDir</li>
  107.      * <li>string $fileName</li>
  108.      * <li>array(stat) $fileInfo</li>
  109.      * </ul>
  110.      *
  111.      * See {@see findRecursiveCallback()} for an example of a callback function.
  112.      *
  113.      * Filters are regular expressions and are therefore required to have
  114.      * starting and ending delimiters. The Perl Compatible syntax is used as
  115.      * regular expression language.
  116.      *
  117.      * @param string         $sourceDir 
  118.      * @param array(string)  $includeFilters 
  119.      * @param array(string)  $excludeFilters 
  120.      * @param callback       $callback 
  121.      * @param mixed          $callbackContext 
  122.      *
  123.      * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not
  124.      *          a directory or does not exist.
  125.      * @throws ezcBaseFilePermissionException if the $sourceDir directory could
  126.      *          not be opened for reading.
  127.      * @return array 
  128.      */
  129.     static public function walkRecursive$sourceDirarray $includeFilters array()array $excludeFilters array()$callback&$callbackContext )
  130.     {
  131.         if !is_dir$sourceDir ) )
  132.         {
  133.             throw new ezcBaseFileNotFoundException$sourceDir'directory' );
  134.         }
  135.         $elements array();
  136.         $d @dir$sourceDir );
  137.         if !$d )
  138.         {
  139.             throw new ezcBaseFilePermissionException$sourceDirezcBaseFileException::READ );
  140.         }
  141.  
  142.         while ( ( $entry $d->read() ) !== false )
  143.         {
  144.             if $entry == '.' || $entry == '..' )
  145.             {
  146.                 continue;
  147.             }
  148.  
  149.             $fileInfo @stat$sourceDir DIRECTORY_SEPARATOR $entry );
  150.             if !$fileInfo )
  151.             {
  152.                 $fileInfo array'size' => 0'mode' => );
  153.             }
  154.  
  155.             if $fileInfo['mode'0x4000 )
  156.             {
  157.                 // We need to ignore the Permission exceptions here as it can
  158.                 // be normal that a directory can not be accessed. We only need
  159.                 // the exception if the top directory could not be read.
  160.                 try
  161.                 {
  162.                     call_user_func_array$callbackarray$callbackContext$sourceDir$entry$fileInfo ) );
  163.                     $subList self::walkRecursive$sourceDir DIRECTORY_SEPARATOR $entry$includeFilters$excludeFilters$callback$callbackContext );
  164.                     $elements array_merge$elements$subList );
  165.                 }
  166.                 catch ezcBaseFilePermissionException $e )
  167.                 {
  168.                 }
  169.             }
  170.             else
  171.             {
  172.                 // By default a file is included in the return list
  173.                 $ok true;
  174.                 // Iterate over the $includeFilters and prohibit the file from
  175.                 // being returned when atleast one of them does not match
  176.                 foreach $includeFilters as $filter )
  177.                 {
  178.                     if !preg_match$filter$sourceDir DIRECTORY_SEPARATOR $entry ) )
  179.                     {
  180.                         $ok false;
  181.                         break;
  182.                     }
  183.                 }
  184.                 // Iterate over the $excludeFilters and prohibit the file from
  185.                 // being returns when atleast one of them matches
  186.                 foreach $excludeFilters as $filter )
  187.                 {
  188.                     if preg_match$filter$sourceDir DIRECTORY_SEPARATOR $entry ) )
  189.                     {
  190.                         $ok false;
  191.                         break;
  192.                     }
  193.                 }
  194.  
  195.                 // If everything's allright, call the callback and add the
  196.                 // entry to the elements array
  197.                 if $ok )
  198.                 {
  199.                     call_user_func$callback$callbackContext$sourceDir$entry$fileInfo );
  200.                     $elements[$sourceDir DIRECTORY_SEPARATOR $entry;
  201.                 }
  202.             }
  203.         }
  204.         sort$elements );
  205.         return $elements;
  206.     }
  207.  
  208.     /**
  209.      * Finds files recursively on a file system
  210.      *
  211.      * With this method you can scan the file system for files. You can use
  212.      * $includeFilters to include only specific files, and $excludeFilters to
  213.      * exclude certain files from being returned. The function will always go
  214.      * into subdirectories even if the entry would not have passed the filters.
  215.      * It uses the {@see walkRecursive()} method to do the actually recursion.
  216.      *
  217.      * Filters are regular expressions and are therefore required to have
  218.      * starting and ending delimiters. The Perl Compatible syntax is used as
  219.      * regular expression language.
  220.      *
  221.      * If you pass an empty array to the $statistics argument, the function
  222.      * will in details about the number of files found into the 'count' array
  223.      * element, and the total filesize in the 'size' array element. Because this
  224.      * argument is passed by reference, you *have* to pass a variable and you
  225.      * can not pass a constant value such as "array()".
  226.      *
  227.      * @param string         $sourceDir 
  228.      * @param array(string)  $includeFilters 
  229.      * @param array(string)  $excludeFilters 
  230.      * @param array()        $statistics 
  231.      *
  232.      * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not
  233.      *          a directory or does not exist.
  234.      * @throws ezcBaseFilePermissionException if the $sourceDir directory could
  235.      *          not be opened for reading.
  236.      * @return array 
  237.      */
  238.     static public function findRecursive$sourceDirarray $includeFilters array()array $excludeFilters array()&$statistics null )
  239.     {
  240.         // init statistics array
  241.         if !is_array$statistics || !array_key_exists'size'$statistics || !array_key_exists'count'$statistics ) )
  242.         {
  243.             $statistics['size']  0;
  244.             $statistics['count'0;
  245.         }
  246.  
  247.         // create the context, and then start walking over the array
  248.         $context new ezcBaseFileFindContext;
  249.         self::walkRecursive$sourceDir$includeFilters$excludeFiltersarray'ezcBaseFile''findRecursiveCallback' )$context );
  250.  
  251.         // collect the statistics
  252.         $statistics['size'$context->size;
  253.         $statistics['count'$context->count;
  254.  
  255.         // return the found and pattern-matched files
  256.         sort$context->elements );
  257.         return $context->elements;
  258.     }
  259.  
  260.  
  261.     /**
  262.      * Removes files and directories recursively from a file system
  263.      *
  264.      * This method recursively removes the $directory and all its contents.
  265.      * You should be <b>extremely</b> careful with this method as it has the
  266.      * potential to erase everything that the current user has access to.
  267.      *
  268.      * @param string $directory 
  269.      */
  270.     static public function removeRecursive$directory )
  271.     {
  272.         $sourceDir realpath$directory );
  273.         if !$sourceDir )
  274.         {
  275.             throw new ezcBaseFileNotFoundException$directory'directory' );
  276.         }
  277.         $d @dir$sourceDir );
  278.         if !$d )
  279.         {
  280.             throw new ezcBaseFilePermissionException$directoryezcBaseFileException::READ );
  281.         }
  282.         // check if we can remove the dir
  283.         $parentDir realpath$directory DIRECTORY_SEPARATOR '..' );
  284.         if !is_writable$parentDir ) )
  285.         {
  286.             throw new ezcBaseFilePermissionException$parentDirezcBaseFileException::WRITE );
  287.         }
  288.         // loop over contents
  289.         while ( ( $entry $d->read() ) !== false )
  290.         {
  291.             if $entry == '.' || $entry == '..' )
  292.             {
  293.                 continue;
  294.             }
  295.  
  296.             if is_dir$sourceDir DIRECTORY_SEPARATOR $entry ) )
  297.             {
  298.                 self::removeRecursive$sourceDir DIRECTORY_SEPARATOR $entry );
  299.             }
  300.             else
  301.             {
  302.                 if @unlink$sourceDir DIRECTORY_SEPARATOR $entry === false )
  303.                 {
  304.                     throw new ezcBaseFilePermissionException$directory DIRECTORY_SEPARATOR $entryezcBaseFileException::REMOVE );
  305.                 }
  306.             }
  307.         }
  308.         $d->close();
  309.         rmdir$sourceDir );
  310.     }
  311.  
  312.     /**
  313.     * Recursively copy a file or directory.
  314.     *
  315.     * Recursively copy a file or directory in $source to the given
  316.     * destination. If a depth is given, the operation will stop, if the given
  317.     * recursion depth is reached. A depth of -1 means no limit, while a depth
  318.     * of 0 means, that only the current file or directory will be copied,
  319.     * without any recursion.
  320.     *
  321.     * You may optionally define modes used to create files and directories.
  322.     *
  323.     * @throws ezcBaseFileNotFoundException
  324.     *       If the $sourceDir directory is not a directory or does not exist.
  325.     * @throws ezcBaseFilePermissionException
  326.     *       If the $sourceDir directory could not be opened for reading, or the
  327.     *       destination is not writeable.
  328.     *
  329.     * @param string $source 
  330.     * @param string $destination 
  331.     * @param int $depth 
  332.     * @param int $dirMode 
  333.     * @param int $fileMode 
  334.     * @return void 
  335.     */
  336.     static public function copyRecursive$source$destination$depth = -1$dirMode 0775$fileMode 0664 )
  337.     {
  338.         // Check if source file exists at all.
  339.         if !is_file$source && !is_dir$source ) )
  340.         {
  341.             throw new ezcBaseFileNotFoundException$source );
  342.         }
  343.  
  344.         // Destination file should NOT exist
  345.         if is_file$destination || is_dir$destination ) )
  346.         {
  347.             throw new ezcBaseFilePermissionException$destinationezcBaseFileException::WRITE );
  348.         }
  349.  
  350.         // Skip non readable files in source directory
  351.         if !is_readable$source ) )
  352.         {
  353.             return;
  354.         }
  355.  
  356.         // Copy
  357.         if is_dir$source ) )
  358.         {
  359.             mkdir$destination );
  360.             // To ignore umask, umask() should not be changed with
  361.             // multithreaded servers...
  362.             chmod$destination$dirMode );
  363.         }
  364.         elseif is_file$source ) )
  365.         {
  366.             copy$source$destination );
  367.             chmod$destination$fileMode );
  368.         }
  369.  
  370.         if ( ( $depth === ||
  371.             !is_dir$source ) ) )
  372.         {
  373.             // Do not recurse (any more)
  374.             return;
  375.         }
  376.  
  377.         // Recurse
  378.         $dh opendir$source );
  379.         while ( ( $file readdir$dh ) ) !== false )
  380.         {
  381.             if ( ( $file === '.' ||
  382.                 $file === '..' ) )
  383.             {
  384.                 continue;
  385.             }
  386.  
  387.             self::copyRecursive(
  388.                 $source '/' $file,
  389.                 $destination '/' $file,
  390.                 $depth 1$dirMode$fileMode
  391.             );
  392.         }
  393.     }
  394.  
  395.     /**
  396.      * Calculates the relative path of the file/directory '$path' to a given
  397.      * $base path.
  398.      *
  399.      * $path and $base should be fully absolute paths. This function returns the
  400.      * answer of "How do I go from $base to $path". If the $path and $base are
  401.      * the same path, the function returns '.'. This method does not touch the
  402.      * filesystem.
  403.      *
  404.      * @param string $path 
  405.      * @param string $base 
  406.      * @return string 
  407.      */
  408.     static public function calculateRelativePath$path$base )
  409.     {
  410.         // Sanitize the paths to use the correct directory separator for the platform
  411.         $path strtr$path'\\/'DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR );
  412.         $base strtr$base'\\/'DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR );
  413.  
  414.         $base explodeDIRECTORY_SEPARATOR$base );
  415.         $path explodeDIRECTORY_SEPARATOR$path );
  416.  
  417.         // If the paths are the same we return
  418.         if $base === $path )
  419.         {
  420.             return '.';
  421.         }
  422.  
  423.         $result '';
  424.  
  425.         $pathPart array_shift$path );
  426.         $basePart array_shift$base );
  427.         while $pathPart == $basePart )
  428.         {
  429.             $pathPart array_shift$path );
  430.             $basePart array_shift$base );
  431.         }
  432.  
  433.         if $pathPart != null )
  434.         {
  435.             array_unshift$path$pathPart );
  436.         }
  437.         if $basePart != null )
  438.         {
  439.             array_unshift$base$basePart );
  440.         }
  441.  
  442.         $result str_repeat'..' DIRECTORY_SEPARATORcount$base ) );
  443.         // prevent a trailing DIRECTORY_SEPARATOR in case there is only a ..
  444.         if count$path == )
  445.         {
  446.             $result substr$result0-strlenDIRECTORY_SEPARATOR ) );
  447.         }
  448.         $result .= joinDIRECTORY_SEPARATOR$path );
  449.  
  450.         return $result;
  451.     }
  452.  
  453.     /**
  454.      * Returns whether the passed $path is an absolute path, giving the current $os.
  455.      *
  456.      * With the $os parameter you can tell this function to use the semantics
  457.      * for a different operating system to determine whether a path is
  458.      * absolute. The $os argument defaults to the OS that the script is running
  459.      * on.
  460.      *
  461.      * @param string $path 
  462.      * @param string $os 
  463.      * @return bool 
  464.      */
  465.     public static function isAbsolutePath$path$os null )
  466.     {
  467.         if $os === null )
  468.         {
  469.             $os ezcBaseFeatures::os();
  470.         }
  471.  
  472.         // Stream wrapper like phar can also be considered absolute paths
  473.         if preg_match'(^[a-z]{3,}://)S'$path ) )
  474.         {
  475.             return true;
  476.         }
  477.  
  478.         switch $os )
  479.         {
  480.             case 'Windows':
  481.                 // Sanitize the paths to use the correct directory separator for the platform
  482.                 $path strtr$path'\\/''\\\\' );
  483.  
  484.                 // Absolute paths with drive letter: X:\
  485.                 if preg_match'@^[A-Z]:\\\\@i'$path ) )
  486.                 {
  487.                     return true;
  488.                 }
  489.  
  490.                 // Absolute paths with network paths: \\server\share\
  491.                 if preg_match'@^\\\\\\\\[A-Z]+\\\\[^\\\\]@i'$path ) )
  492.                 {
  493.                     return true;
  494.                 }
  495.                 break;
  496.             case 'Mac':
  497.             case 'Linux':
  498.             case 'FreeBSD':
  499.             default:
  500.                 // Sanitize the paths to use the correct directory separator for the platform
  501.                 $path strtr$path'\\/''//' );
  502.  
  503.                 if $path[0== '/' )
  504.                 {
  505.                     return true;
  506.                 }
  507.         }
  508.         return false;
  509.     }
  510. }
  511. ?>
Documentation generated by phpDocumentor 1.4.3