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

Documentation generated by phpDocumentor 1.4.3