PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-admin/includes/file.php

https://gitlab.com/endomorphosis/reservationtelco
PHP | 1039 lines | 623 code | 162 blank | 254 comment | 221 complexity | d35041a7e16bda1db95b4a19203ae2b2 MD5 | raw file
  1. <?php
  2. /**
  3. * File contains all the administration image manipulation functions.
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. */
  8. /** The descriptions for theme files. */
  9. $wp_file_descriptions = array (
  10. 'index.php' => __( 'Main Index Template' ),
  11. 'style.css' => __( 'Stylesheet' ),
  12. 'editor-style.css' => __( 'Visual Editor Stylesheet' ),
  13. 'rtl.css' => __( 'RTL Stylesheet' ),
  14. 'comments.php' => __( 'Comments' ),
  15. 'comments-popup.php' => __( 'Popup Comments' ),
  16. 'footer.php' => __( 'Footer' ),
  17. 'header.php' => __( 'Header' ),
  18. 'sidebar.php' => __( 'Sidebar' ),
  19. 'archive.php' => __( 'Archives' ),
  20. 'author.php' => __( 'Author Template' ),
  21. 'tag.php' => __( 'Tag Template' ),
  22. 'category.php' => __( 'Category Template' ),
  23. 'page.php' => __( 'Page Template' ),
  24. 'search.php' => __( 'Search Results' ),
  25. 'searchform.php' => __( 'Search Form' ),
  26. 'single.php' => __( 'Single Post' ),
  27. '404.php' => __( '404 Template' ),
  28. 'link.php' => __( 'Links Template' ),
  29. 'functions.php' => __( 'Theme Functions' ),
  30. 'attachment.php' => __( 'Attachment Template' ),
  31. 'image.php' => __('Image Attachment Template'),
  32. 'video.php' => __('Video Attachment Template'),
  33. 'audio.php' => __('Audio Attachment Template'),
  34. 'application.php' => __('Application Attachment Template'),
  35. 'my-hacks.php' => __( 'my-hacks.php (legacy hacks support)' ),
  36. '.htaccess' => __( '.htaccess (for rewrite rules )' ),
  37. // Deprecated files
  38. 'wp-layout.css' => __( 'Stylesheet' ), 'wp-comments.php' => __( 'Comments Template' ), 'wp-comments-popup.php' => __( 'Popup Comments Template' ));
  39. /**
  40. * {@internal Missing Short Description}}
  41. *
  42. * @since unknown
  43. *
  44. * @param unknown_type $file
  45. * @return unknown
  46. */
  47. function get_file_description( $file ) {
  48. global $wp_file_descriptions;
  49. if ( isset( $wp_file_descriptions[basename( $file )] ) ) {
  50. return $wp_file_descriptions[basename( $file )];
  51. }
  52. elseif ( file_exists( $file ) && is_file( $file ) ) {
  53. $template_data = implode( '', file( $file ) );
  54. if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ))
  55. return _cleanup_header_comment($name[1]) . ' Page Template';
  56. }
  57. return basename( $file );
  58. }
  59. /**
  60. * {@internal Missing Short Description}}
  61. *
  62. * @since unknown
  63. *
  64. * @return unknown
  65. */
  66. function get_home_path() {
  67. $home = get_option( 'home' );
  68. $siteurl = get_option( 'siteurl' );
  69. if ( $home != '' && $home != $siteurl ) {
  70. $wp_path_rel_to_home = str_replace($home, '', $siteurl); /* $siteurl - $home */
  71. $pos = strpos($_SERVER["SCRIPT_FILENAME"], $wp_path_rel_to_home);
  72. $home_path = substr($_SERVER["SCRIPT_FILENAME"], 0, $pos);
  73. $home_path = trailingslashit( $home_path );
  74. } else {
  75. $home_path = ABSPATH;
  76. }
  77. return $home_path;
  78. }
  79. /**
  80. * {@internal Missing Short Description}}
  81. *
  82. * @since unknown
  83. *
  84. * @param unknown_type $file
  85. * @return unknown
  86. */
  87. function get_real_file_to_edit( $file ) {
  88. if ('index.php' == $file || '.htaccess' == $file ) {
  89. $real_file = get_home_path() . $file;
  90. } else {
  91. $real_file = WP_CONTENT_DIR . $file;
  92. }
  93. return $real_file;
  94. }
  95. /**
  96. * Returns a listing of all files in the specified folder and all subdirectories up to 100 levels deep.
  97. * The depth of the recursiveness can be controlled by the $levels param.
  98. *
  99. * @since 2.6.0
  100. *
  101. * @param string $folder Full path to folder
  102. * @param int $levels (optional) Levels of folders to follow, Default: 100 (PHP Loop limit).
  103. * @return bool|array False on failure, Else array of files
  104. */
  105. function list_files( $folder = '', $levels = 100 ) {
  106. if ( empty($folder) )
  107. return false;
  108. if ( ! $levels )
  109. return false;
  110. $files = array();
  111. if ( $dir = @opendir( $folder ) ) {
  112. while (($file = readdir( $dir ) ) !== false ) {
  113. if ( in_array($file, array('.', '..') ) )
  114. continue;
  115. if ( is_dir( $folder . '/' . $file ) ) {
  116. $files2 = list_files( $folder . '/' . $file, $levels - 1);
  117. if ( $files2 )
  118. $files = array_merge($files, $files2 );
  119. else
  120. $files[] = $folder . '/' . $file . '/';
  121. } else {
  122. $files[] = $folder . '/' . $file;
  123. }
  124. }
  125. }
  126. @closedir( $dir );
  127. return $files;
  128. }
  129. /**
  130. * Determines a writable directory for temporary files.
  131. * Function's preference is to WP_CONTENT_DIR followed by the return value of <code>sys_get_temp_dir()</code>, before finally defaulting to /tmp/
  132. *
  133. * In the event that this function does not find a writable location, It may be overridden by the <code>WP_TEMP_DIR</code> constant in your <code>wp-config.php</code> file.
  134. *
  135. * @since 2.5.0
  136. *
  137. * @return string Writable temporary directory
  138. */
  139. function get_temp_dir() {
  140. static $temp;
  141. if ( defined('WP_TEMP_DIR') )
  142. return trailingslashit(WP_TEMP_DIR);
  143. if ( $temp )
  144. return trailingslashit($temp);
  145. $temp = WP_CONTENT_DIR . '/';
  146. if ( is_dir($temp) && @is_writable($temp) )
  147. return $temp;
  148. if ( function_exists('sys_get_temp_dir') ) {
  149. $temp = sys_get_temp_dir();
  150. if ( @is_writable($temp) )
  151. return trailingslashit($temp);
  152. }
  153. $temp = ini_get('upload_tmp_dir');
  154. if ( is_dir($temp) && @is_writable($temp) )
  155. return trailingslashit($temp);
  156. $temp = '/tmp/';
  157. return $temp;
  158. }
  159. /**
  160. * Returns a filename of a Temporary unique file.
  161. * Please note that the calling function must unlink() this itself.
  162. *
  163. * The filename is based off the passed parameter or defaults to the current unix timestamp,
  164. * while the directory can either be passed as well, or by leaving it blank, default to a writable temporary directory.
  165. *
  166. * @since 2.6.0
  167. *
  168. * @param string $filename (optional) Filename to base the Unique file off
  169. * @param string $dir (optional) Directory to store the file in
  170. * @return string a writable filename
  171. */
  172. function wp_tempnam($filename = '', $dir = '') {
  173. if ( empty($dir) )
  174. $dir = get_temp_dir();
  175. $filename = basename($filename);
  176. if ( empty($filename) )
  177. $filename = time();
  178. $filename = preg_replace('|\..*$|', '.tmp', $filename);
  179. $filename = $dir . wp_unique_filename($dir, $filename);
  180. touch($filename);
  181. return $filename;
  182. }
  183. /**
  184. * {@internal Missing Short Description}}
  185. *
  186. * @since unknown
  187. *
  188. * @param unknown_type $file
  189. * @param unknown_type $allowed_files
  190. * @return unknown
  191. */
  192. function validate_file_to_edit( $file, $allowed_files = '' ) {
  193. $code = validate_file( $file, $allowed_files );
  194. if (!$code )
  195. return $file;
  196. switch ( $code ) {
  197. case 1 :
  198. wp_die( __('Sorry, can&#8217;t edit files with &#8220;..&#8221; in the name. If you are trying to edit a file in your WordPress home directory, you can just type the name of the file in.' ));
  199. //case 2 :
  200. // wp_die( __('Sorry, can&#8217;t call files with their real path.' ));
  201. case 3 :
  202. wp_die( __('Sorry, that file cannot be edited.' ));
  203. }
  204. }
  205. /**
  206. * {@internal Missing Short Description}}
  207. *
  208. * @since unknown
  209. *
  210. * @param array $file Reference to a single element of $_FILES. Call the function once for each uploaded file.
  211. * @param array $overrides Optional. An associative array of names=>values to override default variables with extract( $overrides, EXTR_OVERWRITE ).
  212. * @return array On success, returns an associative array of file attributes. On failure, returns $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
  213. */
  214. function wp_handle_upload( &$file, $overrides = false, $time = null ) {
  215. // The default error handler.
  216. if ( ! function_exists( 'wp_handle_upload_error' ) ) {
  217. function wp_handle_upload_error( &$file, $message ) {
  218. return array( 'error'=>$message );
  219. }
  220. }
  221. $file = apply_filters( 'wp_handle_upload_prefilter', $file );
  222. // You may define your own function and pass the name in $overrides['upload_error_handler']
  223. $upload_error_handler = 'wp_handle_upload_error';
  224. // You may have had one or more 'wp_handle_upload_prefilter' functions error out the file. Handle that gracefully.
  225. if ( isset( $file['error'] ) && !is_numeric( $file['error'] ) && $file['error'] )
  226. return $upload_error_handler( $file, $file['error'] );
  227. // You may define your own function and pass the name in $overrides['unique_filename_callback']
  228. $unique_filename_callback = null;
  229. // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
  230. $action = 'wp_handle_upload';
  231. // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
  232. $upload_error_strings = array( false,
  233. __( "The uploaded file exceeds the <code>upload_max_filesize</code> directive in <code>php.ini</code>." ),
  234. __( "The uploaded file exceeds the <em>MAX_FILE_SIZE</em> directive that was specified in the HTML form." ),
  235. __( "The uploaded file was only partially uploaded." ),
  236. __( "No file was uploaded." ),
  237. '',
  238. __( "Missing a temporary folder." ),
  239. __( "Failed to write file to disk." ),
  240. __( "File upload stopped by extension." ));
  241. // All tests are on by default. Most can be turned off by $override[{test_name}] = false;
  242. $test_form = true;
  243. $test_size = true;
  244. $test_upload = true;
  245. // If you override this, you must provide $ext and $type!!!!
  246. $test_type = true;
  247. $mimes = false;
  248. // Install user overrides. Did we mention that this voids your warranty?
  249. if ( is_array( $overrides ) )
  250. extract( $overrides, EXTR_OVERWRITE );
  251. // A correct form post will pass this test.
  252. if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
  253. return call_user_func($upload_error_handler, $file, __( 'Invalid form submission.' ));
  254. // A successful upload will pass this test. It makes no sense to override this one.
  255. if ( $file['error'] > 0 )
  256. return call_user_func($upload_error_handler, $file, $upload_error_strings[$file['error']] );
  257. // A non-empty file will pass this test.
  258. if ( $test_size && !($file['size'] > 0 ) ) {
  259. if ( is_multisite() )
  260. $error_msg = __( 'File is empty. Please upload something more substantial.' );
  261. else
  262. $error_msg = __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' );
  263. return call_user_func($upload_error_handler, $file, $error_msg);
  264. }
  265. // A properly uploaded file will pass this test. There should be no reason to override this one.
  266. if ( $test_upload && ! @ is_uploaded_file( $file['tmp_name'] ) )
  267. return call_user_func($upload_error_handler, $file, __( 'Specified file failed upload test.' ));
  268. // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
  269. if ( $test_type ) {
  270. $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
  271. extract( $wp_filetype );
  272. // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
  273. if ( $proper_filename )
  274. $file['name'] = $proper_filename;
  275. if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
  276. return call_user_func($upload_error_handler, $file, __( 'File type does not meet security guidelines. Try another.' ));
  277. if ( !$ext )
  278. $ext = ltrim(strrchr($file['name'], '.'), '.');
  279. if ( !$type )
  280. $type = $file['type'];
  281. } else {
  282. $type = '';
  283. }
  284. // A writable uploads dir will pass this test. Again, there's no point overriding this one.
  285. if ( ! ( ( $uploads = wp_upload_dir($time) ) && false === $uploads['error'] ) )
  286. return call_user_func($upload_error_handler, $file, $uploads['error'] );
  287. $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
  288. // Move the file to the uploads dir
  289. $new_file = $uploads['path'] . "/$filename";
  290. if ( false === @ move_uploaded_file( $file['tmp_name'], $new_file ) )
  291. return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $uploads['path'] ) );
  292. // Set correct file permissions
  293. $stat = stat( dirname( $new_file ));
  294. $perms = $stat['mode'] & 0000666;
  295. @ chmod( $new_file, $perms );
  296. // Compute the URL
  297. $url = $uploads['url'] . "/$filename";
  298. if ( is_multisite() )
  299. delete_transient( 'dirsize_cache' );
  300. return apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ), 'upload' );
  301. }
  302. /**
  303. * {@internal Missing Short Description}}
  304. *
  305. * Pass this function an array similar to that of a $_FILES POST array.
  306. *
  307. * @since unknown
  308. *
  309. * @param unknown_type $file
  310. * @param unknown_type $overrides
  311. * @return unknown
  312. */
  313. function wp_handle_sideload( &$file, $overrides = false ) {
  314. // The default error handler.
  315. if (! function_exists( 'wp_handle_upload_error' ) ) {
  316. function wp_handle_upload_error( &$file, $message ) {
  317. return array( 'error'=>$message );
  318. }
  319. }
  320. // You may define your own function and pass the name in $overrides['upload_error_handler']
  321. $upload_error_handler = 'wp_handle_upload_error';
  322. // You may define your own function and pass the name in $overrides['unique_filename_callback']
  323. $unique_filename_callback = null;
  324. // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
  325. $action = 'wp_handle_sideload';
  326. // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
  327. $upload_error_strings = array( false,
  328. __( "The uploaded file exceeds the <code>upload_max_filesize</code> directive in <code>php.ini</code>." ),
  329. __( "The uploaded file exceeds the <em>MAX_FILE_SIZE</em> directive that was specified in the HTML form." ),
  330. __( "The uploaded file was only partially uploaded." ),
  331. __( "No file was uploaded." ),
  332. '',
  333. __( "Missing a temporary folder." ),
  334. __( "Failed to write file to disk." ),
  335. __( "File upload stopped by extension." ));
  336. // All tests are on by default. Most can be turned off by $override[{test_name}] = false;
  337. $test_form = true;
  338. $test_size = true;
  339. // If you override this, you must provide $ext and $type!!!!
  340. $test_type = true;
  341. $mimes = false;
  342. // Install user overrides. Did we mention that this voids your warranty?
  343. if ( is_array( $overrides ) )
  344. extract( $overrides, EXTR_OVERWRITE );
  345. // A correct form post will pass this test.
  346. if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
  347. return $upload_error_handler( $file, __( 'Invalid form submission.' ));
  348. // A successful upload will pass this test. It makes no sense to override this one.
  349. if ( ! empty( $file['error'] ) )
  350. return $upload_error_handler( $file, $upload_error_strings[$file['error']] );
  351. // A non-empty file will pass this test.
  352. if ( $test_size && !(filesize($file['tmp_name']) > 0 ) )
  353. return $upload_error_handler( $file, __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini.' ));
  354. // A properly uploaded file will pass this test. There should be no reason to override this one.
  355. if (! @ is_file( $file['tmp_name'] ) )
  356. return $upload_error_handler( $file, __( 'Specified file does not exist.' ));
  357. // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
  358. if ( $test_type ) {
  359. $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
  360. extract( $wp_filetype );
  361. // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
  362. if ( $proper_filename )
  363. $file['name'] = $proper_filename;
  364. if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
  365. return $upload_error_handler( $file, __( 'File type does not meet security guidelines. Try another.' ));
  366. if ( !$ext )
  367. $ext = ltrim(strrchr($file['name'], '.'), '.');
  368. if ( !$type )
  369. $type = $file['type'];
  370. }
  371. // A writable uploads dir will pass this test. Again, there's no point overriding this one.
  372. if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) )
  373. return $upload_error_handler( $file, $uploads['error'] );
  374. $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
  375. // Strip the query strings.
  376. $filename = str_replace('?','-', $filename);
  377. $filename = str_replace('&','-', $filename);
  378. // Move the file to the uploads dir
  379. $new_file = $uploads['path'] . "/$filename";
  380. if ( false === @ rename( $file['tmp_name'], $new_file ) ) {
  381. return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $uploads['path'] ) );
  382. }
  383. // Set correct file permissions
  384. $stat = stat( dirname( $new_file ));
  385. $perms = $stat['mode'] & 0000666;
  386. @ chmod( $new_file, $perms );
  387. // Compute the URL
  388. $url = $uploads['url'] . "/$filename";
  389. $return = apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ), 'sideload' );
  390. return $return;
  391. }
  392. /**
  393. * Downloads a url to a local temporary file using the WordPress HTTP Class.
  394. * Please note, That the calling function must unlink() the file.
  395. *
  396. * @since 2.5.0
  397. *
  398. * @param string $url the URL of the file to download
  399. * @return mixed WP_Error on failure, string Filename on success.
  400. */
  401. function download_url( $url ) {
  402. //WARNING: The file is not automatically deleted, The script must unlink() the file.
  403. if ( ! $url )
  404. return new WP_Error('http_no_url', __('Invalid URL Provided.'));
  405. $tmpfname = wp_tempnam($url);
  406. if ( ! $tmpfname )
  407. return new WP_Error('http_no_file', __('Could not create Temporary file.'));
  408. $handle = @fopen($tmpfname, 'wb');
  409. if ( ! $handle )
  410. return new WP_Error('http_no_file', __('Could not create Temporary file.'));
  411. $response = wp_remote_get($url, array('timeout' => 300));
  412. if ( is_wp_error($response) ) {
  413. fclose($handle);
  414. unlink($tmpfname);
  415. return $response;
  416. }
  417. if ( $response['response']['code'] != '200' ){
  418. fclose($handle);
  419. unlink($tmpfname);
  420. return new WP_Error('http_404', trim($response['response']['message']));
  421. }
  422. fwrite($handle, $response['body']);
  423. fclose($handle);
  424. return $tmpfname;
  425. }
  426. /**
  427. * Unzip's a specified ZIP file to a location on the Filesystem via the WordPress Filesystem Abstraction.
  428. * Assumes that WP_Filesystem() has already been called and set up. Does not extract a root-level __MACOSX directory, if present.
  429. *
  430. * Attempts to increase the PHP Memory limit to 256M before uncompressing,
  431. * However, The most memory required shouldn't be much larger than the Archive itself.
  432. *
  433. * @since 2.5.0
  434. *
  435. * @param string $file Full path and filename of zip archive
  436. * @param string $to Full path on the filesystem to extract archive to
  437. * @return mixed WP_Error on failure, True on success
  438. */
  439. function unzip_file($file, $to) {
  440. global $wp_filesystem;
  441. if ( ! $wp_filesystem || !is_object($wp_filesystem) )
  442. return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
  443. // Unzip can use a lot of memory, but not this much hopefully
  444. @ini_set('memory_limit', '256M');
  445. $needed_dirs = array();
  446. $to = trailingslashit($to);
  447. // Determine any parent dir's needed (of the upgrade directory)
  448. if ( ! $wp_filesystem->is_dir($to) ) { //Only do parents if no children exist
  449. $path = preg_split('![/\\\]!', untrailingslashit($to));
  450. for ( $i = count($path); $i >= 0; $i-- ) {
  451. if ( empty($path[$i]) )
  452. continue;
  453. $dir = implode('/', array_slice($path, 0, $i+1) );
  454. if ( preg_match('!^[a-z]:$!i', $dir) ) // Skip it if it looks like a Windows Drive letter.
  455. continue;
  456. if ( ! $wp_filesystem->is_dir($dir) )
  457. $needed_dirs[] = $dir;
  458. else
  459. break; // A folder exists, therefor, we dont need the check the levels below this
  460. }
  461. }
  462. if ( class_exists('ZipArchive') && apply_filters('unzip_file_use_ziparchive', true ) ) {
  463. $result = _unzip_file_ziparchive($file, $to, $needed_dirs);
  464. if ( true === $result ) {
  465. return $result;
  466. } elseif ( is_wp_error($result) ) {
  467. if ( 'incompatible_archive' != $result->get_error_code() )
  468. return $result;
  469. }
  470. }
  471. // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file.
  472. return _unzip_file_pclzip($file, $to, $needed_dirs);
  473. }
  474. /**
  475. * This function should not be called directly, use unzip_file instead. Attempts to unzip an archive using the ZipArchive class.
  476. * Assumes that WP_Filesystem() has already been called and set up.
  477. *
  478. * @since 3.0.0
  479. * @see unzip_file
  480. * @access private
  481. *
  482. * @param string $file Full path and filename of zip archive
  483. * @param string $to Full path on the filesystem to extract archive to
  484. * @param array $needed_dirs A partial list of required folders needed to be created.
  485. * @return mixed WP_Error on failure, True on success
  486. */
  487. function _unzip_file_ziparchive($file, $to, $needed_dirs = array() ) {
  488. global $wp_filesystem;
  489. $z = new ZipArchive();
  490. // PHP4-compat - php4 classes can't contain constants
  491. $zopen = $z->open($file, /* ZIPARCHIVE::CHECKCONS */ 4);
  492. if ( true !== $zopen )
  493. return new WP_Error('incompatible_archive', __('Incompatible Archive.'));
  494. for ( $i = 0; $i < $z->numFiles; $i++ ) {
  495. if ( ! $info = $z->statIndex($i) )
  496. return new WP_Error('stat_failed', __('Could not retrieve file from archive.'));
  497. if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Skip the OS X-created __MACOSX directory
  498. continue;
  499. if ( '/' == substr($info['name'], -1) ) // directory
  500. $needed_dirs[] = $to . untrailingslashit($info['name']);
  501. else
  502. $needed_dirs[] = $to . untrailingslashit(dirname($info['name']));
  503. }
  504. $needed_dirs = array_unique($needed_dirs);
  505. foreach ( $needed_dirs as $dir ) {
  506. // Check the parent folders of the folders all exist within the creation array.
  507. if ( untrailingslashit($to) == $dir ) // Skip over the working directory, We know this exists (or will exist)
  508. continue;
  509. $parent_folder = dirname($dir);
  510. while ( !empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs) ) {
  511. $needed_dirs[] = $parent_folder;
  512. $parent_folder = dirname($parent_folder);
  513. }
  514. }
  515. asort($needed_dirs);
  516. // Create those directories if need be:
  517. foreach ( $needed_dirs as $_dir ) {
  518. if ( ! $wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && ! $wp_filesystem->is_dir($_dir) ) // Only check to see if the Dir exists upon creation failure. Less I/O this way.
  519. return new WP_Error('mkdir_failed', __('Could not create directory.'), $_dir);
  520. }
  521. unset($needed_dirs);
  522. for ( $i = 0; $i < $z->numFiles; $i++ ) {
  523. if ( ! $info = $z->statIndex($i) )
  524. return new WP_Error('stat_failed', __('Could not retrieve file from archive.'));
  525. if ( '/' == substr($info['name'], -1) ) // directory
  526. continue;
  527. if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Don't extract the OS X-created __MACOSX directory files
  528. continue;
  529. $contents = $z->getFromIndex($i);
  530. if ( false === $contents )
  531. return new WP_Error('extract_failed', __('Could not extract file from archive.'), $info['name']);
  532. if ( ! $wp_filesystem->put_contents( $to . $info['name'], $contents, FS_CHMOD_FILE) )
  533. return new WP_Error('copy_failed', __('Could not copy file.'), $to . $info['filename']);
  534. }
  535. $z->close();
  536. return true;
  537. }
  538. /**
  539. * This function should not be called directly, use unzip_file instead. Attempts to unzip an archive using the PclZip library.
  540. * Assumes that WP_Filesystem() has already been called and set up.
  541. *
  542. * @since 3.0.0
  543. * @see unzip_file
  544. * @access private
  545. *
  546. * @param string $file Full path and filename of zip archive
  547. * @param string $to Full path on the filesystem to extract archive to
  548. * @param array $needed_dirs A partial list of required folders needed to be created.
  549. * @return mixed WP_Error on failure, True on success
  550. */
  551. function _unzip_file_pclzip($file, $to, $needed_dirs = array()) {
  552. global $wp_filesystem;
  553. require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php');
  554. $archive = new PclZip($file);
  555. // Is the archive valid?
  556. if ( false == ($archive_files = $archive->extract(PCLZIP_OPT_EXTRACT_AS_STRING)) )
  557. return new WP_Error('incompatible_archive', __('Incompatible Archive.'), $archive->errorInfo(true));
  558. if ( 0 == count($archive_files) )
  559. return new WP_Error('empty_archive', __('Empty archive.'));
  560. // Determine any children directories needed (From within the archive)
  561. foreach ( $archive_files as $file ) {
  562. if ( '__MACOSX/' === substr($file['filename'], 0, 9) ) // Skip the OS X-created __MACOSX directory
  563. continue;
  564. $needed_dirs[] = $to . untrailingslashit( $file['folder'] ? $file['filename'] : dirname($file['filename']) );
  565. }
  566. $needed_dirs = array_unique($needed_dirs);
  567. foreach ( $needed_dirs as $dir ) {
  568. // Check the parent folders of the folders all exist within the creation array.
  569. if ( untrailingslashit($to) == $dir ) // Skip over the working directory, We know this exists (or will exist)
  570. continue;
  571. $parent_folder = dirname($dir);
  572. while ( !empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs) ) {
  573. $needed_dirs[] = $parent_folder;
  574. $parent_folder = dirname($parent_folder);
  575. }
  576. }
  577. asort($needed_dirs);
  578. // Create those directories if need be:
  579. foreach ( $needed_dirs as $_dir ) {
  580. if ( ! $wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && ! $wp_filesystem->is_dir($_dir) ) // Only check to see if the dir exists upon creation failure. Less I/O this way.
  581. return new WP_Error('mkdir_failed', __('Could not create directory.'), $_dir);
  582. }
  583. unset($needed_dirs);
  584. // Extract the files from the zip
  585. foreach ( $archive_files as $file ) {
  586. if ( $file['folder'] )
  587. continue;
  588. if ( '__MACOSX/' === substr($file['filename'], 0, 9) ) // Don't extract the OS X-created __MACOSX directory files
  589. continue;
  590. if ( ! $wp_filesystem->put_contents( $to . $file['filename'], $file['content'], FS_CHMOD_FILE) )
  591. return new WP_Error('copy_failed', __('Could not copy file.'), $to . $file['filename']);
  592. }
  593. return true;
  594. }
  595. /**
  596. * Copies a directory from one location to another via the WordPress Filesystem Abstraction.
  597. * Assumes that WP_Filesystem() has already been called and setup.
  598. *
  599. * @since 2.5.0
  600. *
  601. * @param string $from source directory
  602. * @param string $to destination directory
  603. * @return mixed WP_Error on failure, True on success.
  604. */
  605. function copy_dir($from, $to) {
  606. global $wp_filesystem;
  607. $dirlist = $wp_filesystem->dirlist($from);
  608. $from = trailingslashit($from);
  609. $to = trailingslashit($to);
  610. foreach ( (array) $dirlist as $filename => $fileinfo ) {
  611. if ( 'f' == $fileinfo['type'] ) {
  612. if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true) ) {
  613. // If copy failed, chmod file to 0644 and try again.
  614. $wp_filesystem->chmod($to . $filename, 0644);
  615. if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true) )
  616. return new WP_Error('copy_failed', __('Could not copy file.'), $to . $filename);
  617. }
  618. $wp_filesystem->chmod($to . $filename, FS_CHMOD_FILE);
  619. } elseif ( 'd' == $fileinfo['type'] ) {
  620. if ( !$wp_filesystem->is_dir($to . $filename) ) {
  621. if ( !$wp_filesystem->mkdir($to . $filename, FS_CHMOD_DIR) )
  622. return new WP_Error('mkdir_failed', __('Could not create directory.'), $to . $filename);
  623. }
  624. $result = copy_dir($from . $filename, $to . $filename);
  625. if ( is_wp_error($result) )
  626. return $result;
  627. }
  628. }
  629. return true;
  630. }
  631. /**
  632. * Initialises and connects the WordPress Filesystem Abstraction classes.
  633. * This function will include the chosen transport and attempt connecting.
  634. *
  635. * Plugins may add extra transports, And force WordPress to use them by returning the filename via the 'filesystem_method_file' filter.
  636. *
  637. * @since 2.5.0
  638. *
  639. * @param array $args (optional) Connection args, These are passed directly to the WP_Filesystem_*() classes.
  640. * @param string $context (optional) Context for get_filesystem_method(), See function declaration for more information.
  641. * @return boolean false on failure, true on success
  642. */
  643. function WP_Filesystem( $args = false, $context = false ) {
  644. global $wp_filesystem;
  645. require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
  646. $method = get_filesystem_method($args, $context);
  647. if ( ! $method )
  648. return false;
  649. if ( ! class_exists("WP_Filesystem_$method") ) {
  650. $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method);
  651. if ( ! file_exists($abstraction_file) )
  652. return;
  653. require_once($abstraction_file);
  654. }
  655. $method = "WP_Filesystem_$method";
  656. $wp_filesystem = new $method($args);
  657. //Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default.
  658. if ( ! defined('FS_CONNECT_TIMEOUT') )
  659. define('FS_CONNECT_TIMEOUT', 30);
  660. if ( ! defined('FS_TIMEOUT') )
  661. define('FS_TIMEOUT', 30);
  662. if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
  663. return false;
  664. if ( !$wp_filesystem->connect() )
  665. return false; //There was an erorr connecting to the server.
  666. // Set the permission constants if not already set.
  667. if ( ! defined('FS_CHMOD_DIR') )
  668. define('FS_CHMOD_DIR', 0755 );
  669. if ( ! defined('FS_CHMOD_FILE') )
  670. define('FS_CHMOD_FILE', 0644 );
  671. return true;
  672. }
  673. /**
  674. * Determines which Filesystem Method to use.
  675. * The priority of the Transports are: Direct, SSH2, FTP PHP Extension, FTP Sockets (Via Sockets class, or fsoxkopen())
  676. *
  677. * Note that the return value of this function can be overridden in 2 ways
  678. * - By defining FS_METHOD in your <code>wp-config.php</code> file
  679. * - By using the filesystem_method filter
  680. * Valid values for these are: 'direct', 'ssh', 'ftpext' or 'ftpsockets'
  681. * Plugins may also define a custom transport handler, See the WP_Filesystem function for more information.
  682. *
  683. * @since 2.5.0
  684. *
  685. * @param array $args Connection details.
  686. * @param string $context Full path to the directory that is tested for being writable.
  687. * @return string The transport to use, see description for valid return values.
  688. */
  689. function get_filesystem_method($args = array(), $context = false) {
  690. $method = defined('FS_METHOD') ? FS_METHOD : false; //Please ensure that this is either 'direct', 'ssh', 'ftpext' or 'ftpsockets'
  691. if ( ! $method && function_exists('getmyuid') && function_exists('fileowner') ){
  692. if ( !$context )
  693. $context = WP_CONTENT_DIR;
  694. $context = trailingslashit($context);
  695. $temp_file_name = $context . 'temp-write-test-' . time();
  696. $temp_handle = @fopen($temp_file_name, 'w');
  697. if ( $temp_handle ) {
  698. if ( getmyuid() == @fileowner($temp_file_name) )
  699. $method = 'direct';
  700. @fclose($temp_handle);
  701. @unlink($temp_file_name);
  702. }
  703. }
  704. if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
  705. if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
  706. if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
  707. return apply_filters('filesystem_method', $method, $args);
  708. }
  709. /**
  710. * Displays a form to the user to request for their FTP/SSH details in order to connect to the filesystem.
  711. * All chosen/entered details are saved, Excluding the Password.
  712. *
  713. * Hostnames may be in the form of hostname:portnumber (eg: wordpress.org:2467) to specify an alternate FTP/SSH port.
  714. *
  715. * Plugins may override this form by returning true|false via the <code>request_filesystem_credentials</code> filter.
  716. *
  717. * @since 2.5.0
  718. *
  719. * @param string $form_post the URL to post the form to
  720. * @param string $type the chosen Filesystem method in use
  721. * @param boolean $error if the current request has failed to connect
  722. * @param string $context The directory which is needed access to, The write-test will be performed on this directory by get_filesystem_method()
  723. * @param string $extra_fields Extra POST fields which should be checked for to be included in the post.
  724. * @return boolean False on failure. True on success.
  725. */
  726. function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null) {
  727. $req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields );
  728. if ( '' !== $req_cred )
  729. return $req_cred;
  730. if ( empty($type) )
  731. $type = get_filesystem_method(array(), $context);
  732. if ( 'direct' == $type )
  733. return true;
  734. if ( is_null( $extra_fields ) )
  735. $extra_fields = array( 'version', 'locale' );
  736. $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
  737. // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
  738. $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? stripslashes($_POST['hostname']) : $credentials['hostname']);
  739. $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? stripslashes($_POST['username']) : $credentials['username']);
  740. $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? stripslashes($_POST['password']) : '');
  741. // Check to see if we are setting the public/private keys for ssh
  742. $credentials['public_key'] = defined('FTP_PUBKEY') ? FTP_PUBKEY : (!empty($_POST['public_key']) ? stripslashes($_POST['public_key']) : '');
  743. $credentials['private_key'] = defined('FTP_PRIKEY') ? FTP_PRIKEY : (!empty($_POST['private_key']) ? stripslashes($_POST['private_key']) : '');
  744. //sanitize the hostname, Some people might pass in odd-data:
  745. $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
  746. if ( strpos($credentials['hostname'], ':') ) {
  747. list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
  748. if ( ! is_numeric($credentials['port']) )
  749. unset($credentials['port']);
  750. } else {
  751. unset($credentials['port']);
  752. }
  753. if ( (defined('FTP_SSH') && FTP_SSH) || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
  754. $credentials['connection_type'] = 'ssh';
  755. else if ( (defined('FTP_SSL') && FTP_SSL) && 'ftpext' == $type ) //Only the FTP Extension understands SSL
  756. $credentials['connection_type'] = 'ftps';
  757. else if ( !empty($_POST['connection_type']) )
  758. $credentials['connection_type'] = stripslashes($_POST['connection_type']);
  759. else if ( !isset($credentials['connection_type']) ) //All else fails (And its not defaulted to something else saved), Default to FTP
  760. $credentials['connection_type'] = 'ftp';
  761. if ( ! $error &&
  762. (
  763. ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
  764. ( 'ssh' == $credentials['connection_type'] && !empty($credentials['public_key']) && !empty($credentials['private_key']) )
  765. ) ) {
  766. $stored_credentials = $credentials;
  767. if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
  768. $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
  769. unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
  770. update_option('ftp_credentials', $stored_credentials);
  771. return $credentials;
  772. }
  773. $hostname = '';
  774. $username = '';
  775. $password = '';
  776. $connection_type = '';
  777. if ( !empty($credentials) )
  778. extract($credentials, EXTR_OVERWRITE);
  779. if ( $error ) {
  780. $error_string = __('<strong>Error:</strong> There was an error connecting to the server, Please verify the settings are correct.');
  781. if ( is_wp_error($error) )
  782. $error_string = $error->get_error_message();
  783. echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
  784. }
  785. $types = array();
  786. if ( extension_loaded('ftp') || extension_loaded('sockets') || function_exists('fsockopen') )
  787. $types[ 'ftp' ] = __('FTP');
  788. if ( extension_loaded('ftp') ) //Only this supports FTPS
  789. $types[ 'ftps' ] = __('FTPS (SSL)');
  790. if ( extension_loaded('ssh2') && function_exists('stream_get_contents') )
  791. $types[ 'ssh' ] = __('SSH2');
  792. $types = apply_filters('fs_ftp_connection_types', $types, $credentials, $type, $error, $context);
  793. ?>
  794. <script type="text/javascript">
  795. <!--
  796. jQuery(function($){
  797. jQuery("#ssh").click(function () {
  798. jQuery("#ssh_keys").show();
  799. });
  800. jQuery("#ftp, #ftps").click(function () {
  801. jQuery("#ssh_keys").hide();
  802. });
  803. jQuery('form input[value=""]:first').focus();
  804. });
  805. -->
  806. </script>
  807. <form action="<?php echo $form_post ?>" method="post">
  808. <div class="wrap">
  809. <?php screen_icon(); ?>
  810. <h2><?php _e('Connection Information') ?></h2>
  811. <p><?php
  812. _e('To perform the requested action, WordPress needs to access to your web server.');
  813. echo ' ';
  814. if ( ( isset( $types['ftp'] ) || isset( $types['ftps'] ) ) ) {
  815. if ( isset( $types['ssh'] ) )
  816. _e('Please enter your FTP or SSH credentials to proceed.');
  817. else
  818. _e('Please enter your FTP credentials to proceed.');
  819. echo ' ';
  820. }
  821. _e('If you do not remember your credentials, you should contact your web host.');
  822. ?></p>
  823. <table class="form-table">
  824. <tr valign="top">
  825. <th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
  826. <td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php disabled( defined('FTP_HOST') ); ?> size="40" /></td>
  827. </tr>
  828. <tr valign="top">
  829. <th scope="row"><label for="username"><?php _e('Username') ?></label></th>
  830. <td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php disabled( defined('FTP_USER') ); ?> size="40" /></td>
  831. </tr>
  832. <tr valign="top">
  833. <th scope="row"><label for="password"><?php _e('Password') ?></label></th>
  834. <td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php disabled( defined('FTP_PASS') ); ?> size="40" /></td>
  835. </tr>
  836. <?php if ( isset($types['ssh']) ) : ?>
  837. <tr id="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
  838. <th scope="row"><?php _e('Authentication Keys') ?>
  839. <div class="key-labels textright">
  840. <label for="public_key"><?php _e('Public Key:') ?></label ><br />
  841. <label for="private_key"><?php _e('Private Key:') ?></label>
  842. </div></th>
  843. <td><br /><input name="public_key" type="text" id="public_key" value="<?php echo esc_attr($public_key) ?>"<?php disabled( defined('FTP_PUBKEY') ); ?> size="40" /><br /><input name="private_key" type="text" id="private_key" value="<?php echo esc_attr($private_key) ?>"<?php disabled( defined('FTP_PRIKEY') ); ?> size="40" />
  844. <div><?php _e('Enter the location on the server where the keys are located. If a passphrase is needed, enter that in the password field above.') ?></div></td>
  845. </tr>
  846. <?php endif; ?>
  847. <tr valign="top">
  848. <th scope="row"><?php _e('Connection Type') ?></th>
  849. <td>
  850. <fieldset><legend class="screen-reader-text"><span><?php _e('Connection Type') ?></span></legend>
  851. <?php
  852. $disabled = disabled( (defined('FTP_SSL') && FTP_SSL) || (defined('FTP_SSH') && FTP_SSH), true, false );
  853. foreach ( $types as $name => $text ) : ?>
  854. <label for="<?php echo esc_attr($name) ?>">
  855. <input type="radio" name="connection_type" id="<?php echo esc_attr($name) ?>" value="<?php echo esc_attr($name) ?>"<?php checked($name, $connection_type); echo $disabled; ?> />
  856. <?php echo $text ?>
  857. </label>
  858. <?php endforeach; ?>
  859. </fieldset>
  860. </td>
  861. </tr>
  862. </table>
  863. <?php
  864. foreach ( (array) $extra_fields as $field ) {
  865. if ( isset( $_POST[ $field ] ) )
  866. echo '<input type="hidden" name="' . esc_attr( $field ) . '" value="' . esc_attr( stripslashes( $_POST[ $field ] ) ) . '" />';
  867. }
  868. ?>
  869. <p class="submit">
  870. <input id="upgrade" name="upgrade" type="submit" class="button" value="<?php esc_attr_e('Proceed'); ?>" />
  871. </p>
  872. </div>
  873. </form>
  874. <?php
  875. return false;
  876. }
  877. ?>