PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-admin/includes/file.php

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