[44] | 1 | <?php
|
---|
| 2 | /**
|
---|
| 3 | * File contains all the administration image manipulation functions.
|
---|
| 4 | *
|
---|
| 5 | * @package WordPress
|
---|
| 6 | * @subpackage Administration
|
---|
| 7 | */
|
---|
| 8 |
|
---|
| 9 | /** The descriptions for theme files. */
|
---|
| 10 | $wp_file_descriptions = array (
|
---|
| 11 | 'index.php' => __( 'Main Index Template' ),
|
---|
| 12 | 'style.css' => __( '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 | 'category.php' => __( 'Category Template' ),
|
---|
| 21 | 'page.php' => __( 'Page Template' ),
|
---|
| 22 | 'search.php' => __( 'Search Results' ),
|
---|
| 23 | 'searchform.php' => __( 'Search Form' ),
|
---|
| 24 | 'single.php' => __( 'Single Post' ),
|
---|
| 25 | '404.php' => __( '404 Template' ),
|
---|
| 26 | 'link.php' => __( 'Links Template' ),
|
---|
| 27 | 'functions.php' => __( 'Theme Functions' ),
|
---|
| 28 | 'attachment.php' => __( 'Attachment Template' ),
|
---|
| 29 | 'image.php' => __('Image Attachment Template'),
|
---|
| 30 | 'video.php' => __('Video Attachment Template'),
|
---|
| 31 | 'audio.php' => __('Audio Attachment Template'),
|
---|
| 32 | 'application.php' => __('Application Attachment Template'),
|
---|
| 33 | 'my-hacks.php' => __( 'my-hacks.php (legacy hacks support)' ),
|
---|
| 34 | '.htaccess' => __( '.htaccess (for rewrite rules )' ),
|
---|
| 35 | // Deprecated files
|
---|
| 36 | 'wp-layout.css' => __( 'Stylesheet' ), 'wp-comments.php' => __( 'Comments Template' ), 'wp-comments-popup.php' => __( 'Popup Comments Template' ));
|
---|
| 37 |
|
---|
| 38 | /**
|
---|
| 39 | * {@internal Missing Short Description}}
|
---|
| 40 | *
|
---|
| 41 | * @since unknown
|
---|
| 42 | *
|
---|
| 43 | * @param unknown_type $file
|
---|
| 44 | * @return unknown
|
---|
| 45 | */
|
---|
| 46 | function get_file_description( $file ) {
|
---|
| 47 | global $wp_file_descriptions;
|
---|
| 48 |
|
---|
| 49 | if ( isset( $wp_file_descriptions[basename( $file )] ) ) {
|
---|
| 50 | return $wp_file_descriptions[basename( $file )];
|
---|
| 51 | }
|
---|
| 52 | elseif ( file_exists( WP_CONTENT_DIR . $file ) && is_file( WP_CONTENT_DIR . $file ) ) {
|
---|
| 53 | $template_data = implode( '', file( WP_CONTENT_DIR . $file ) );
|
---|
| 54 | if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ))
|
---|
| 55 | return _cleanup_header_comment($name[1]) . ' Page Template';
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | return basename( $file );
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | /**
|
---|
| 62 | * {@internal Missing Short Description}}
|
---|
| 63 | *
|
---|
| 64 | * @since unknown
|
---|
| 65 | *
|
---|
| 66 | * @return unknown
|
---|
| 67 | */
|
---|
| 68 | function get_home_path() {
|
---|
| 69 | $home = get_option( 'home' );
|
---|
| 70 | $siteurl = get_option( 'siteurl' );
|
---|
| 71 | if ( $home != '' && $home != $siteurl ) {
|
---|
| 72 | $wp_path_rel_to_home = str_replace($home, '', $siteurl); /* $siteurl - $home */
|
---|
| 73 | $pos = strpos($_SERVER["SCRIPT_FILENAME"], $wp_path_rel_to_home);
|
---|
| 74 | $home_path = substr($_SERVER["SCRIPT_FILENAME"], 0, $pos);
|
---|
| 75 | $home_path = trailingslashit( $home_path );
|
---|
| 76 | } else {
|
---|
| 77 | $home_path = ABSPATH;
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | return $home_path;
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | /**
|
---|
| 84 | * {@internal Missing Short Description}}
|
---|
| 85 | *
|
---|
| 86 | * @since unknown
|
---|
| 87 | *
|
---|
| 88 | * @param unknown_type $file
|
---|
| 89 | * @return unknown
|
---|
| 90 | */
|
---|
| 91 | function get_real_file_to_edit( $file ) {
|
---|
| 92 | if ('index.php' == $file || '.htaccess' == $file ) {
|
---|
| 93 | $real_file = get_home_path() . $file;
|
---|
| 94 | } else {
|
---|
| 95 | $real_file = WP_CONTENT_DIR . $file;
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | return $real_file;
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | /**
|
---|
| 102 | * {@internal Missing Short Description}}
|
---|
| 103 | *
|
---|
| 104 | * @since unknown
|
---|
| 105 | *
|
---|
| 106 | * @param string $folder Optional. Full path to folder
|
---|
| 107 | * @param int $levels Optional. Levels of folders to follow, Default: 100 (PHP Loop limit).
|
---|
| 108 | * @return bool|array
|
---|
| 109 | */
|
---|
| 110 | function list_files( $folder = '', $levels = 100 ) {
|
---|
| 111 | if( empty($folder) )
|
---|
| 112 | return false;
|
---|
| 113 |
|
---|
| 114 | if( ! $levels )
|
---|
| 115 | return false;
|
---|
| 116 |
|
---|
| 117 | $files = array();
|
---|
| 118 | if ( $dir = @opendir( $folder ) ) {
|
---|
| 119 | while (($file = readdir( $dir ) ) !== false ) {
|
---|
| 120 | if ( in_array($file, array('.', '..') ) )
|
---|
| 121 | continue;
|
---|
| 122 | if ( is_dir( $folder . '/' . $file ) ) {
|
---|
| 123 | $files2 = list_files( $folder . '/' . $file, $levels - 1);
|
---|
| 124 | if( $files2 )
|
---|
| 125 | $files = array_merge($files, $files2 );
|
---|
| 126 | else
|
---|
| 127 | $files[] = $folder . '/' . $file . '/';
|
---|
| 128 | } else {
|
---|
| 129 | $files[] = $folder . '/' . $file;
|
---|
| 130 | }
|
---|
| 131 | }
|
---|
| 132 | }
|
---|
| 133 | @closedir( $dir );
|
---|
| 134 | return $files;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | /**
|
---|
| 138 | * {@internal Missing Short Description}}
|
---|
| 139 | *
|
---|
| 140 | * @since unknown
|
---|
| 141 | *
|
---|
| 142 | * @return unknown
|
---|
| 143 | */
|
---|
| 144 | function get_temp_dir() {
|
---|
| 145 | if ( defined('WP_TEMP_DIR') )
|
---|
| 146 | return trailingslashit(WP_TEMP_DIR);
|
---|
| 147 |
|
---|
| 148 | $temp = WP_CONTENT_DIR . '/';
|
---|
| 149 | if ( is_dir($temp) && is_writable($temp) )
|
---|
| 150 | return $temp;
|
---|
| 151 |
|
---|
| 152 | if ( function_exists('sys_get_temp_dir') )
|
---|
| 153 | return trailingslashit(sys_get_temp_dir());
|
---|
| 154 |
|
---|
| 155 | return '/tmp/';
|
---|
| 156 | }
|
---|
| 157 |
|
---|
| 158 | /**
|
---|
| 159 | * {@internal Missing Short Description}}
|
---|
| 160 | *
|
---|
| 161 | * @since unknown
|
---|
| 162 | *
|
---|
| 163 | * @param unknown_type $filename
|
---|
| 164 | * @param unknown_type $dir
|
---|
| 165 | * @return unknown
|
---|
| 166 | */
|
---|
| 167 | function wp_tempnam($filename = '', $dir = ''){
|
---|
| 168 | if ( empty($dir) )
|
---|
| 169 | $dir = get_temp_dir();
|
---|
| 170 | $filename = basename($filename);
|
---|
| 171 | if ( empty($filename) )
|
---|
| 172 | $filename = time();
|
---|
| 173 |
|
---|
| 174 | $filename = $dir . wp_unique_filename($dir, $filename);
|
---|
| 175 | touch($filename);
|
---|
| 176 | return $filename;
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | /**
|
---|
| 180 | * {@internal Missing Short Description}}
|
---|
| 181 | *
|
---|
| 182 | * @since unknown
|
---|
| 183 | *
|
---|
| 184 | * @param unknown_type $file
|
---|
| 185 | * @param unknown_type $allowed_files
|
---|
| 186 | * @return unknown
|
---|
| 187 | */
|
---|
| 188 | function validate_file_to_edit( $file, $allowed_files = '' ) {
|
---|
| 189 | $file = stripslashes( $file );
|
---|
| 190 |
|
---|
| 191 | $code = validate_file( $file, $allowed_files );
|
---|
| 192 |
|
---|
| 193 | if (!$code )
|
---|
| 194 | return $file;
|
---|
| 195 |
|
---|
| 196 | switch ( $code ) {
|
---|
| 197 | case 1 :
|
---|
| 198 | wp_die( __('Sorry, can’t edit files with “..” 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 |
|
---|
| 200 | case 2 :
|
---|
| 201 | wp_die( __('Sorry, can’t call files with their real path.' ));
|
---|
| 202 |
|
---|
| 203 | case 3 :
|
---|
| 204 | wp_die( __('Sorry, that file cannot be edited.' ));
|
---|
| 205 | }
|
---|
| 206 | }
|
---|
| 207 |
|
---|
| 208 | /**
|
---|
| 209 | * {@internal Missing Short Description}}
|
---|
| 210 | *
|
---|
| 211 | * @since unknown
|
---|
| 212 | *
|
---|
| 213 | * @param array $file Reference to a single element of $_FILES. Call the function once for each uploaded file.
|
---|
| 214 | * @param array $overrides Optional. An associative array of names=>values to override default variables with extract( $overrides, EXTR_OVERWRITE ).
|
---|
| 215 | * @return array On success, returns an associative array of file attributes. On failure, returns $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
|
---|
| 216 | */
|
---|
| 217 | function wp_handle_upload( &$file, $overrides = false, $time = null ) {
|
---|
| 218 | // The default error handler.
|
---|
| 219 | if (! function_exists( 'wp_handle_upload_error' ) ) {
|
---|
| 220 | function wp_handle_upload_error( &$file, $message ) {
|
---|
| 221 | return array( 'error'=>$message );
|
---|
| 222 | }
|
---|
| 223 | }
|
---|
| 224 |
|
---|
| 225 | // You may define your own function and pass the name in $overrides['upload_error_handler']
|
---|
| 226 | $upload_error_handler = 'wp_handle_upload_error';
|
---|
| 227 |
|
---|
| 228 | // You may define your own function and pass the name in $overrides['unique_filename_callback']
|
---|
| 229 | $unique_filename_callback = null;
|
---|
| 230 |
|
---|
| 231 | // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
|
---|
| 232 | $action = 'wp_handle_upload';
|
---|
| 233 |
|
---|
| 234 | // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
|
---|
| 235 | $upload_error_strings = array( false,
|
---|
| 236 | __( "The uploaded file exceeds the <code>upload_max_filesize</code> directive in <code>php.ini</code>." ),
|
---|
| 237 | __( "The uploaded file exceeds the <em>MAX_FILE_SIZE</em> directive that was specified in the HTML form." ),
|
---|
| 238 | __( "The uploaded file was only partially uploaded." ),
|
---|
| 239 | __( "No file was uploaded." ),
|
---|
| 240 | '',
|
---|
| 241 | __( "Missing a temporary folder." ),
|
---|
| 242 | __( "Failed to write file to disk." ),
|
---|
| 243 | __( "File upload stopped by extension." ));
|
---|
| 244 |
|
---|
| 245 | // All tests are on by default. Most can be turned off by $override[{test_name}] = false;
|
---|
| 246 | $test_form = true;
|
---|
| 247 | $test_size = true;
|
---|
| 248 |
|
---|
| 249 | // If you override this, you must provide $ext and $type!!!!
|
---|
| 250 | $test_type = true;
|
---|
| 251 | $mimes = false;
|
---|
| 252 |
|
---|
| 253 | // Install user overrides. Did we mention that this voids your warranty?
|
---|
| 254 | if ( is_array( $overrides ) )
|
---|
| 255 | extract( $overrides, EXTR_OVERWRITE );
|
---|
| 256 |
|
---|
| 257 | // A correct form post will pass this test.
|
---|
| 258 | if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
|
---|
| 259 | return $upload_error_handler( $file, __( 'Invalid form submission.' ));
|
---|
| 260 |
|
---|
| 261 | // A successful upload will pass this test. It makes no sense to override this one.
|
---|
| 262 | if ( $file['error'] > 0 )
|
---|
| 263 | return $upload_error_handler( $file, $upload_error_strings[$file['error']] );
|
---|
| 264 |
|
---|
| 265 | // A non-empty file will pass this test.
|
---|
| 266 | if ( $test_size && !($file['size'] > 0 ) )
|
---|
| 267 | 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.' ));
|
---|
| 268 |
|
---|
| 269 | // A properly uploaded file will pass this test. There should be no reason to override this one.
|
---|
| 270 | if (! @ is_uploaded_file( $file['tmp_name'] ) )
|
---|
| 271 | return $upload_error_handler( $file, __( 'Specified file failed upload test.' ));
|
---|
| 272 |
|
---|
| 273 | // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
|
---|
| 274 | if ( $test_type ) {
|
---|
| 275 | $wp_filetype = wp_check_filetype( $file['name'], $mimes );
|
---|
| 276 |
|
---|
| 277 | extract( $wp_filetype );
|
---|
| 278 |
|
---|
| 279 | if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
|
---|
| 280 | return $upload_error_handler( $file, __( 'File type does not meet security guidelines. Try another.' ));
|
---|
| 281 |
|
---|
| 282 | if ( !$ext )
|
---|
| 283 | $ext = ltrim(strrchr($file['name'], '.'), '.');
|
---|
| 284 |
|
---|
| 285 | if ( !$type )
|
---|
| 286 | $type = $file['type'];
|
---|
| 287 | } else {
|
---|
| 288 | $type = '';
|
---|
| 289 | }
|
---|
| 290 |
|
---|
| 291 | // A writable uploads dir will pass this test. Again, there's no point overriding this one.
|
---|
| 292 | if ( ! ( ( $uploads = wp_upload_dir($time) ) && false === $uploads['error'] ) )
|
---|
| 293 | return $upload_error_handler( $file, $uploads['error'] );
|
---|
| 294 |
|
---|
| 295 | $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
|
---|
| 296 |
|
---|
| 297 | // Move the file to the uploads dir
|
---|
| 298 | $new_file = $uploads['path'] . "/$filename";
|
---|
| 299 | if ( false === @ move_uploaded_file( $file['tmp_name'], $new_file ) ) {
|
---|
| 300 | return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $uploads['path'] ) );
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | // Set correct file permissions
|
---|
| 304 | $stat = stat( dirname( $new_file ));
|
---|
| 305 | $perms = $stat['mode'] & 0000666;
|
---|
| 306 | @ chmod( $new_file, $perms );
|
---|
| 307 |
|
---|
| 308 | // Compute the URL
|
---|
| 309 | $url = $uploads['url'] . "/$filename";
|
---|
| 310 |
|
---|
| 311 | return apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ) );
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | /**
|
---|
| 315 | * {@internal Missing Short Description}}
|
---|
| 316 | *
|
---|
| 317 | * Pass this function an array similar to that of a $_FILES POST array.
|
---|
| 318 | *
|
---|
| 319 | * @since unknown
|
---|
| 320 | *
|
---|
| 321 | * @param unknown_type $file
|
---|
| 322 | * @param unknown_type $overrides
|
---|
| 323 | * @return unknown
|
---|
| 324 | */
|
---|
| 325 | function wp_handle_sideload( &$file, $overrides = false ) {
|
---|
| 326 | // The default error handler.
|
---|
| 327 | if (! function_exists( 'wp_handle_upload_error' ) ) {
|
---|
| 328 | function wp_handle_upload_error( &$file, $message ) {
|
---|
| 329 | return array( 'error'=>$message );
|
---|
| 330 | }
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | // You may define your own function and pass the name in $overrides['upload_error_handler']
|
---|
| 334 | $upload_error_handler = 'wp_handle_upload_error';
|
---|
| 335 |
|
---|
| 336 | // You may define your own function and pass the name in $overrides['unique_filename_callback']
|
---|
| 337 | $unique_filename_callback = null;
|
---|
| 338 |
|
---|
| 339 | // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
|
---|
| 340 | $action = 'wp_handle_sideload';
|
---|
| 341 |
|
---|
| 342 | // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
|
---|
| 343 | $upload_error_strings = array( false,
|
---|
| 344 | __( "The uploaded file exceeds the <code>upload_max_filesize</code> directive in <code>php.ini</code>." ),
|
---|
| 345 | __( "The uploaded file exceeds the <em>MAX_FILE_SIZE</em> directive that was specified in the HTML form." ),
|
---|
| 346 | __( "The uploaded file was only partially uploaded." ),
|
---|
| 347 | __( "No file was uploaded." ),
|
---|
| 348 | '',
|
---|
| 349 | __( "Missing a temporary folder." ),
|
---|
| 350 | __( "Failed to write file to disk." ),
|
---|
| 351 | __( "File upload stopped by extension." ));
|
---|
| 352 |
|
---|
| 353 | // All tests are on by default. Most can be turned off by $override[{test_name}] = false;
|
---|
| 354 | $test_form = true;
|
---|
| 355 | $test_size = true;
|
---|
| 356 |
|
---|
| 357 | // If you override this, you must provide $ext and $type!!!!
|
---|
| 358 | $test_type = true;
|
---|
| 359 | $mimes = false;
|
---|
| 360 |
|
---|
| 361 | // Install user overrides. Did we mention that this voids your warranty?
|
---|
| 362 | if ( is_array( $overrides ) )
|
---|
| 363 | extract( $overrides, EXTR_OVERWRITE );
|
---|
| 364 |
|
---|
| 365 | // A correct form post will pass this test.
|
---|
| 366 | if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
|
---|
| 367 | return $upload_error_handler( $file, __( 'Invalid form submission.' ));
|
---|
| 368 |
|
---|
| 369 | // A successful upload will pass this test. It makes no sense to override this one.
|
---|
| 370 | if ( $file['error'] > 0 )
|
---|
| 371 | return $upload_error_handler( $file, $upload_error_strings[$file['error']] );
|
---|
| 372 |
|
---|
| 373 | // A non-empty file will pass this test.
|
---|
| 374 | if ( $test_size && !(filesize($file['tmp_name']) > 0 ) )
|
---|
| 375 | 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.' ));
|
---|
| 376 |
|
---|
| 377 | // A properly uploaded file will pass this test. There should be no reason to override this one.
|
---|
| 378 | if (! @ is_file( $file['tmp_name'] ) )
|
---|
| 379 | return $upload_error_handler( $file, __( 'Specified file does not exist.' ));
|
---|
| 380 |
|
---|
| 381 | // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
|
---|
| 382 | if ( $test_type ) {
|
---|
| 383 | $wp_filetype = wp_check_filetype( $file['name'], $mimes );
|
---|
| 384 |
|
---|
| 385 | extract( $wp_filetype );
|
---|
| 386 |
|
---|
| 387 | if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
|
---|
| 388 | return $upload_error_handler( $file, __( 'File type does not meet security guidelines. Try another.' ));
|
---|
| 389 |
|
---|
| 390 | if ( !$ext )
|
---|
| 391 | $ext = ltrim(strrchr($file['name'], '.'), '.');
|
---|
| 392 |
|
---|
| 393 | if ( !$type )
|
---|
| 394 | $type = $file['type'];
|
---|
| 395 | }
|
---|
| 396 |
|
---|
| 397 | // A writable uploads dir will pass this test. Again, there's no point overriding this one.
|
---|
| 398 | if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) )
|
---|
| 399 | return $upload_error_handler( $file, $uploads['error'] );
|
---|
| 400 |
|
---|
| 401 | $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
|
---|
| 402 |
|
---|
| 403 | // Strip the query strings.
|
---|
| 404 | $filename = str_replace('?','-', $filename);
|
---|
| 405 | $filename = str_replace('&','-', $filename);
|
---|
| 406 |
|
---|
| 407 | // Move the file to the uploads dir
|
---|
| 408 | $new_file = $uploads['path'] . "/$filename";
|
---|
| 409 | if ( false === @ rename( $file['tmp_name'], $new_file ) ) {
|
---|
| 410 | return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $uploads['path'] ) );
|
---|
| 411 | }
|
---|
| 412 |
|
---|
| 413 | // Set correct file permissions
|
---|
| 414 | $stat = stat( dirname( $new_file ));
|
---|
| 415 | $perms = $stat['mode'] & 0000666;
|
---|
| 416 | @ chmod( $new_file, $perms );
|
---|
| 417 |
|
---|
| 418 | // Compute the URL
|
---|
| 419 | $url = $uploads['url'] . "/$filename";
|
---|
| 420 |
|
---|
| 421 | $return = apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ) );
|
---|
| 422 |
|
---|
| 423 | return $return;
|
---|
| 424 | }
|
---|
| 425 |
|
---|
| 426 | /**
|
---|
| 427 | * Downloads a url to a local file using the Snoopy HTTP Class.
|
---|
| 428 | *
|
---|
| 429 | * @since unknown
|
---|
| 430 | * @todo Transition over to using the new HTTP Request API (jacob).
|
---|
| 431 | *
|
---|
| 432 | * @param string $url the URL of the file to download
|
---|
| 433 | * @return mixed WP_Error on failure, string Filename on success.
|
---|
| 434 | */
|
---|
| 435 | function download_url( $url ) {
|
---|
| 436 | //WARNING: The file is not automatically deleted, The script must unlink() the file.
|
---|
| 437 | if ( ! $url )
|
---|
| 438 | return new WP_Error('http_no_url', __('Invalid URL Provided'));
|
---|
| 439 |
|
---|
| 440 | $tmpfname = wp_tempnam($url);
|
---|
| 441 | if ( ! $tmpfname )
|
---|
| 442 | return new WP_Error('http_no_file', __('Could not create Temporary file'));
|
---|
| 443 |
|
---|
| 444 | $handle = @fopen($tmpfname, 'wb');
|
---|
| 445 | if ( ! $handle )
|
---|
| 446 | return new WP_Error('http_no_file', __('Could not create Temporary file'));
|
---|
| 447 |
|
---|
| 448 | $response = wp_remote_get($url, array('timeout' => 60));
|
---|
| 449 |
|
---|
| 450 | if ( is_wp_error($response) ) {
|
---|
| 451 | fclose($handle);
|
---|
| 452 | unlink($tmpfname);
|
---|
| 453 | return $response;
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | if ( $response['response']['code'] != '200' ){
|
---|
| 457 | fclose($handle);
|
---|
| 458 | unlink($tmpfname);
|
---|
| 459 | return new WP_Error('http_404', trim($response['response']['message']));
|
---|
| 460 | }
|
---|
| 461 |
|
---|
| 462 | fwrite($handle, $response['body']);
|
---|
| 463 | fclose($handle);
|
---|
| 464 |
|
---|
| 465 | return $tmpfname;
|
---|
| 466 | }
|
---|
| 467 |
|
---|
| 468 | /**
|
---|
| 469 | * {@internal Missing Short Description}}
|
---|
| 470 | *
|
---|
| 471 | * @since unknown
|
---|
| 472 | *
|
---|
| 473 | * @param unknown_type $file
|
---|
| 474 | * @param unknown_type $to
|
---|
| 475 | * @return unknown
|
---|
| 476 | */
|
---|
| 477 | function unzip_file($file, $to) {
|
---|
| 478 | global $wp_filesystem;
|
---|
| 479 |
|
---|
| 480 | if ( ! $wp_filesystem || !is_object($wp_filesystem) )
|
---|
| 481 | return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
|
---|
| 482 |
|
---|
| 483 | // Unzip uses a lot of memory
|
---|
| 484 | @ini_set('memory_limit', '256M');
|
---|
| 485 |
|
---|
| 486 | $fs =& $wp_filesystem;
|
---|
| 487 |
|
---|
| 488 | require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php');
|
---|
| 489 |
|
---|
| 490 | $archive = new PclZip($file);
|
---|
| 491 |
|
---|
| 492 | // Is the archive valid?
|
---|
| 493 | if ( false == ($archive_files = $archive->extract(PCLZIP_OPT_EXTRACT_AS_STRING)) )
|
---|
| 494 | return new WP_Error('incompatible_archive', __('Incompatible archive'), $archive->errorInfo(true));
|
---|
| 495 |
|
---|
| 496 | if ( 0 == count($archive_files) )
|
---|
| 497 | return new WP_Error('empty_archive', __('Empty archive'));
|
---|
| 498 |
|
---|
| 499 | $path = explode('/', untrailingslashit($to));
|
---|
| 500 | for ( $i = count($path); $i > 0; $i-- ) { //>0 = first element is empty allways for paths starting with '/'
|
---|
| 501 | $tmppath = implode('/', array_slice($path, 0, $i) );
|
---|
| 502 | if ( $fs->is_dir($tmppath) ) { //Found the highest folder that exists, Create from here(ie +1)
|
---|
| 503 | for ( $i = $i + 1; $i <= count($path); $i++ ) {
|
---|
| 504 | $tmppath = implode('/', array_slice($path, 0, $i) );
|
---|
| 505 | if ( ! $fs->mkdir($tmppath, FS_CHMOD_DIR) )
|
---|
| 506 | return new WP_Error('mkdir_failed', __('Could not create directory'), $tmppath);
|
---|
| 507 | }
|
---|
| 508 | break; //Exit main for loop
|
---|
| 509 | }
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | $to = trailingslashit($to);
|
---|
| 513 | foreach ($archive_files as $file) {
|
---|
| 514 | $path = $file['folder'] ? $file['filename'] : dirname($file['filename']);
|
---|
| 515 | $path = explode('/', $path);
|
---|
| 516 | for ( $i = count($path); $i >= 0; $i-- ) { //>=0 as the first element contains data
|
---|
| 517 | if ( empty($path[$i]) )
|
---|
| 518 | continue;
|
---|
| 519 | $tmppath = $to . implode('/', array_slice($path, 0, $i) );
|
---|
| 520 | if ( $fs->is_dir($tmppath) ) {//Found the highest folder that exists, Create from here
|
---|
| 521 | for ( $i = $i + 1; $i <= count($path); $i++ ) { //< count() no file component please.
|
---|
| 522 | $tmppath = $to . implode('/', array_slice($path, 0, $i) );
|
---|
| 523 | if ( ! $fs->is_dir($tmppath) && ! $fs->mkdir($tmppath, FS_CHMOD_DIR) )
|
---|
| 524 | return new WP_Error('mkdir_failed', __('Could not create directory'), $tmppath);
|
---|
| 525 | }
|
---|
| 526 | break; //Exit main for loop
|
---|
| 527 | }
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | // We've made sure the folders are there, so let's extract the file now:
|
---|
| 531 | if ( ! $file['folder'] ) {
|
---|
| 532 | if ( !$fs->put_contents( $to . $file['filename'], $file['content']) )
|
---|
| 533 | return new WP_Error('copy_failed', __('Could not copy file'), $to . $file['filename']);
|
---|
| 534 | $fs->chmod($to . $file['filename'], FS_CHMOD_FILE);
|
---|
| 535 | }
|
---|
| 536 | }
|
---|
| 537 | return true;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | /**
|
---|
| 541 | * {@internal Missing Short Description}}
|
---|
| 542 | *
|
---|
| 543 | * @since unknown
|
---|
| 544 | *
|
---|
| 545 | * @param unknown_type $from
|
---|
| 546 | * @param unknown_type $to
|
---|
| 547 | * @return unknown
|
---|
| 548 | */
|
---|
| 549 | function copy_dir($from, $to) {
|
---|
| 550 | global $wp_filesystem;
|
---|
| 551 |
|
---|
| 552 | $dirlist = $wp_filesystem->dirlist($from);
|
---|
| 553 |
|
---|
| 554 | $from = trailingslashit($from);
|
---|
| 555 | $to = trailingslashit($to);
|
---|
| 556 |
|
---|
| 557 | foreach ( (array) $dirlist as $filename => $fileinfo ) {
|
---|
| 558 | if ( 'f' == $fileinfo['type'] ) {
|
---|
| 559 | if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true) ) {
|
---|
| 560 | // If copy failed, chmod file to 0644 and try again.
|
---|
| 561 | $wp_filesystem->chmod($to . $filename, 0644);
|
---|
| 562 | if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true) )
|
---|
| 563 | return new WP_Error('copy_failed', __('Could not copy file'), $to . $filename);
|
---|
| 564 | }
|
---|
| 565 | $wp_filesystem->chmod($to . $filename, FS_CHMOD_FILE);
|
---|
| 566 | } elseif ( 'd' == $fileinfo['type'] ) {
|
---|
| 567 | if ( !$wp_filesystem->is_dir($to . $filename) ) {
|
---|
| 568 | if ( !$wp_filesystem->mkdir($to . $filename, FS_CHMOD_DIR) )
|
---|
| 569 | return new WP_Error('mkdir_failed', __('Could not create directory'), $to . $filename);
|
---|
| 570 | }
|
---|
| 571 | $result = copy_dir($from . $filename, $to . $filename);
|
---|
| 572 | if ( is_wp_error($result) )
|
---|
| 573 | return $result;
|
---|
| 574 | }
|
---|
| 575 | }
|
---|
| 576 | }
|
---|
| 577 |
|
---|
| 578 | /**
|
---|
| 579 | * {@internal Missing Short Description}}
|
---|
| 580 | *
|
---|
| 581 | * @since unknown
|
---|
| 582 | *
|
---|
| 583 | * @param unknown_type $args
|
---|
| 584 | * @return unknown
|
---|
| 585 | */
|
---|
| 586 | function WP_Filesystem( $args = false, $context = false ) {
|
---|
| 587 | global $wp_filesystem;
|
---|
| 588 |
|
---|
| 589 | require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
|
---|
| 590 |
|
---|
| 591 | $method = get_filesystem_method($args, $context);
|
---|
| 592 |
|
---|
| 593 | if ( ! $method )
|
---|
| 594 | return false;
|
---|
| 595 |
|
---|
| 596 | if ( ! class_exists("WP_Filesystem_$method") ) {
|
---|
| 597 | $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method);
|
---|
| 598 | if( ! file_exists($abstraction_file) )
|
---|
| 599 | return;
|
---|
| 600 |
|
---|
| 601 | require_once($abstraction_file);
|
---|
| 602 | }
|
---|
| 603 | $method = "WP_Filesystem_$method";
|
---|
| 604 |
|
---|
| 605 | $wp_filesystem = new $method($args);
|
---|
| 606 |
|
---|
| 607 | if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
|
---|
| 608 | return false;
|
---|
| 609 |
|
---|
| 610 | if ( !$wp_filesystem->connect() )
|
---|
| 611 | return false; //There was an erorr connecting to the server.
|
---|
| 612 |
|
---|
| 613 | // Set the permission constants if not already set.
|
---|
| 614 | if ( ! defined('FS_CHMOD_DIR') )
|
---|
| 615 | define('FS_CHMOD_DIR', 0755 );
|
---|
| 616 | if ( ! defined('FS_CHMOD_FILE') )
|
---|
| 617 | define('FS_CHMOD_FILE', 0644 );
|
---|
| 618 |
|
---|
| 619 | return true;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | /**
|
---|
| 623 | * {@internal Missing Short Description}}
|
---|
| 624 | *
|
---|
| 625 | * @since unknown
|
---|
| 626 | *
|
---|
| 627 | * @param unknown_type $args
|
---|
| 628 | * @param string $context Full path to the directory that is tested for being writable.
|
---|
| 629 | * @return unknown
|
---|
| 630 | */
|
---|
| 631 | function get_filesystem_method($args = array(), $context = false) {
|
---|
| 632 | $method = defined('FS_METHOD') ? FS_METHOD : false; //Please ensure that this is either 'direct', 'ssh', 'ftpext' or 'ftpsockets'
|
---|
| 633 |
|
---|
| 634 | if( ! $method && function_exists('getmyuid') && function_exists('fileowner') ){
|
---|
| 635 | if ( !$context )
|
---|
| 636 | $context = WP_CONTENT_DIR;
|
---|
| 637 | $context = trailingslashit($context);
|
---|
| 638 | $temp_file_name = $context . '.write-test-' . time();
|
---|
| 639 | $temp_handle = @fopen($temp_file_name, 'w');
|
---|
| 640 | if ( $temp_handle ) {
|
---|
| 641 | if ( getmyuid() == fileowner($temp_file_name) )
|
---|
| 642 | $method = 'direct';
|
---|
| 643 | @fclose($temp_handle);
|
---|
| 644 | unlink($temp_file_name);
|
---|
| 645 | }
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
|
---|
| 649 | if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
|
---|
| 650 | if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
|
---|
| 651 | return apply_filters('filesystem_method', $method, $args);
|
---|
| 652 | }
|
---|
| 653 |
|
---|
| 654 | /**
|
---|
| 655 | * {@internal Missing Short Description}}
|
---|
| 656 | *
|
---|
| 657 | * @since unknown
|
---|
| 658 | *
|
---|
| 659 | * @param unknown_type $form_post
|
---|
| 660 | * @param unknown_type $type
|
---|
| 661 | * @param unknown_type $error
|
---|
| 662 | * @return unknown
|
---|
| 663 | */
|
---|
| 664 | function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false) {
|
---|
| 665 | $req_cred = apply_filters('request_filesystem_credentials', '', $form_post, $type, $error, $context);
|
---|
| 666 | if ( '' !== $req_cred )
|
---|
| 667 | return $req_cred;
|
---|
| 668 |
|
---|
| 669 | if ( empty($type) )
|
---|
| 670 | $type = get_filesystem_method(array(), $context);
|
---|
| 671 |
|
---|
| 672 | if ( 'direct' == $type )
|
---|
| 673 | return true;
|
---|
| 674 |
|
---|
| 675 | $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
|
---|
| 676 |
|
---|
| 677 | // 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)
|
---|
| 678 | $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? $_POST['hostname'] : $credentials['hostname']);
|
---|
| 679 | $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? $_POST['username'] : $credentials['username']);
|
---|
| 680 | $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? $_POST['password'] : '');
|
---|
| 681 |
|
---|
| 682 | // Check to see if we are setting the public/private keys for ssh
|
---|
| 683 | $credentials['public_key'] = defined('FTP_PUBKEY') ? FTP_PUBKEY : (!empty($_POST['public_key']) ? $_POST['public_key'] : '');
|
---|
| 684 | $credentials['private_key'] = defined('FTP_PRIKEY') ? FTP_PRIKEY : (!empty($_POST['private_key']) ? $_POST['private_key'] : '');
|
---|
| 685 |
|
---|
| 686 | //sanitize the hostname, Some people might pass in odd-data:
|
---|
| 687 | $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
|
---|
| 688 |
|
---|
| 689 | if ( strpos($credentials['hostname'], ':') )
|
---|
| 690 | list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
|
---|
| 691 | else
|
---|
| 692 | unset($credentials['port']);
|
---|
| 693 |
|
---|
| 694 | if ( defined('FTP_SSH') || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
|
---|
| 695 | $credentials['connection_type'] = 'ssh';
|
---|
| 696 | else if ( defined('FTP_SSL') && 'ftpext' == $type ) //Only the FTP Extension understands SSL
|
---|
| 697 | $credentials['connection_type'] = 'ftps';
|
---|
| 698 | else if ( !empty($_POST['connection_type']) )
|
---|
| 699 | $credentials['connection_type'] = $_POST['connection_type'];
|
---|
| 700 | else if ( !isset($credentials['connection_type']) ) //All else fails (And its not defaulted to something else saved), Default to FTP
|
---|
| 701 | $credentials['connection_type'] = 'ftp';
|
---|
| 702 |
|
---|
| 703 | if ( ! $error &&
|
---|
| 704 | (
|
---|
| 705 | ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
|
---|
| 706 | ( 'ssh' == $credentials['connection_type'] && !empty($credentials['public_key']) && !empty($credentials['private_key']) )
|
---|
| 707 | ) ) {
|
---|
| 708 | $stored_credentials = $credentials;
|
---|
| 709 | if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
|
---|
| 710 | $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
|
---|
| 711 |
|
---|
| 712 | unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
|
---|
| 713 | update_option('ftp_credentials', $stored_credentials);
|
---|
| 714 | return $credentials;
|
---|
| 715 | }
|
---|
| 716 | $hostname = '';
|
---|
| 717 | $username = '';
|
---|
| 718 | $password = '';
|
---|
| 719 | $connection_type = '';
|
---|
| 720 | if ( !empty($credentials) )
|
---|
| 721 | extract($credentials, EXTR_OVERWRITE);
|
---|
| 722 | if ( $error ) {
|
---|
| 723 | $error_string = __('<strong>Error:</strong> There was an error connecting to the server, Please verify the settings are correct.');
|
---|
| 724 | if ( is_wp_error($error) )
|
---|
| 725 | $error_string = $error->get_error_message();
|
---|
| 726 | echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
|
---|
| 727 | }
|
---|
| 728 | ?>
|
---|
| 729 | <script type="text/javascript">
|
---|
| 730 | <!--
|
---|
| 731 | jQuery(function($){
|
---|
| 732 | jQuery("#ssh").click(function () {
|
---|
| 733 | jQuery("#ssh_keys").show();
|
---|
| 734 | });
|
---|
| 735 | jQuery("#ftp, #ftps").click(function () {
|
---|
| 736 | jQuery("#ssh_keys").hide();
|
---|
| 737 | });
|
---|
| 738 | jQuery('form input[value=""]:first').focus();
|
---|
| 739 | });
|
---|
| 740 | -->
|
---|
| 741 | </script>
|
---|
| 742 | <form action="<?php echo $form_post ?>" method="post">
|
---|
| 743 | <div class="wrap">
|
---|
| 744 | <?php screen_icon(); ?>
|
---|
| 745 | <h2><?php _e('Connection Information') ?></h2>
|
---|
| 746 | <p><?php _e('To perform the requested action, connection information is required.') ?></p>
|
---|
| 747 |
|
---|
| 748 | <table class="form-table">
|
---|
| 749 | <tr valign="top">
|
---|
| 750 | <th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
|
---|
| 751 | <td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php if( defined('FTP_HOST') ) echo ' disabled="disabled"' ?> size="40" /></td>
|
---|
| 752 | </tr>
|
---|
| 753 |
|
---|
| 754 | <tr valign="top">
|
---|
| 755 | <th scope="row"><label for="username"><?php _e('Username') ?></label></th>
|
---|
| 756 | <td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php if( defined('FTP_USER') ) echo ' disabled="disabled"' ?> size="40" /></td>
|
---|
| 757 | </tr>
|
---|
| 758 |
|
---|
| 759 | <tr valign="top">
|
---|
| 760 | <th scope="row"><label for="password"><?php _e('Password') ?></label></th>
|
---|
| 761 | <td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php if ( defined('FTP_PASS') ) echo ' disabled="disabled"' ?> size="40" /></td>
|
---|
| 762 | </tr>
|
---|
| 763 |
|
---|
| 764 | <?php if ( extension_loaded('ssh2') && function_exists('stream_get_contents') ) : ?>
|
---|
| 765 | <tr id="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
|
---|
| 766 | <th scope="row"><?php _e('Authentication Keys') ?>
|
---|
| 767 | <div class="key-labels textright">
|
---|
| 768 | <label for="public_key"><?php _e('Public Key:') ?></label ><br />
|
---|
| 769 | <label for="private_key"><?php _e('Private Key:') ?></label>
|
---|
| 770 | </div></th>
|
---|
| 771 | <td><br /><input name="public_key" type="text" id="public_key" value="<?php echo esc_attr($public_key) ?>"<?php if( defined('FTP_PUBKEY') ) echo ' disabled="disabled"' ?> size="40" /><br /><input name="private_key" type="text" id="private_key" value="<?php echo esc_attr($private_key) ?>"<?php if( defined('FTP_PRIKEY') ) echo ' disabled="disabled"' ?> size="40" />
|
---|
| 772 | <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>
|
---|
| 773 | </tr>
|
---|
| 774 | <?php endif; ?>
|
---|
| 775 |
|
---|
| 776 | <tr valign="top">
|
---|
| 777 | <th scope="row"><?php _e('Connection Type') ?></th>
|
---|
| 778 | <td>
|
---|
| 779 | <fieldset><legend class="screen-reader-text"><span><?php _e('Connection Type') ?></span></legend>
|
---|
| 780 | <label><input id="ftp" name="connection_type" type="radio" value="ftp" <?php checked('ftp', $connection_type); if ( defined('FTP_SSL') || defined('FTP_SSH') ) echo ' disabled="disabled"'; ?>/> <?php _e('FTP') ?></label>
|
---|
| 781 | <?php if ( 'ftpext' == $type ) : ?>
|
---|
| 782 | <br /><label><input id="ftps" name="connection_type" type="radio" value="ftps" <?php checked('ftps', $connection_type); if ( defined('FTP_SSL') || defined('FTP_SSH') ) echo ' disabled="disabled"'; ?>/> <?php _e('FTPS (SSL)') ?></label>
|
---|
| 783 | <?php endif; ?>
|
---|
| 784 | <?php if ( extension_loaded('ssh2') && function_exists('stream_get_contents') ) : ?>
|
---|
| 785 | <br /><label><input id="ssh" name="connection_type" type="radio" value="ssh" <?php checked('ssh', $connection_type); if ( defined('FTP_SSL') || defined('FTP_SSH') ) echo ' disabled="disabled"'; ?>/> <?php _e('SSH') ?></label>
|
---|
| 786 | <?php endif; ?>
|
---|
| 787 | </fieldset>
|
---|
| 788 | </td>
|
---|
| 789 | </tr>
|
---|
| 790 | </table>
|
---|
| 791 |
|
---|
| 792 | <?php if ( isset( $_POST['version'] ) ) : ?>
|
---|
| 793 | <input type="hidden" name="version" value="<?php echo esc_attr($_POST['version']) ?>" />
|
---|
| 794 | <?php endif; ?>
|
---|
| 795 | <?php if ( isset( $_POST['locale'] ) ) : ?>
|
---|
| 796 | <input type="hidden" name="locale" value="<?php echo esc_attr($_POST['locale']) ?>" />
|
---|
| 797 | <?php endif; ?>
|
---|
| 798 | <p class="submit">
|
---|
| 799 | <input id="upgrade" name="upgrade" type="submit" class="button" value="<?php esc_attr_e('Proceed'); ?>" />
|
---|
| 800 | </p>
|
---|
| 801 | </div>
|
---|
| 802 | </form>
|
---|
| 803 | <?php
|
---|
| 804 | return false;
|
---|
| 805 | }
|
---|
| 806 |
|
---|
| 807 | ?>
|
---|