if (!$tmpfile_name) { $failedFiles[$k] = 'Failed to find temporary directory.'; // no trans: very unlikely continue; } if (!save_to_file($file_contents, $tmpfile_name, 'w')) { unlink($tmpfile_name); $failedFiles[$k] = sprintf('Could not write to temporary file (%s).', $tmpfile_name); continue; } // Fake/inject info into PHP's array of uploaded files. // fp> TODO! This is a nasty dirty hack. That kind of stuff always breaks somewhere down the line. Needs cleanup. // This allows us to treat it (nearly) the same way as regular uploads, apart from // is_uploaded_file(), which we skip and move_uploaded_file() (where we use rename()). $_FILES['uploadfile']['name'][$k] = rawurldecode(basename($parsed_url['path'])); $_FILES['uploadfile']['size'][$k] = evo_bytes($file_contents); $_FILES['uploadfile']['error'][$k] = 0; $_FILES['uploadfile']['tmp_name'][$k] = $tmpfile_name; $_FILES['uploadfile']['_evo_fetched_url'][$k] = $url; // skip is_uploaded_file and keep info unset($file_contents); } else { $failedFiles[$k] = sprintf('Could not retrieve file. Error: %s (status %s). Used method: %s.', $info['error'], isset($info['status']) ? $info['status'] : '-', isset($info['used_method']) ? $info['used_method'] : '-'); } } } } // Process renaming/replacing of old versions: if (!empty($renamedFiles)) { foreach ($renamedFiles as $rKey => $rData) { $replace_old = param('Renamed_' . $rKey, 'string', null);
/** * metaWeblog.newMediaObject image upload * wp.uploadFile * * Supplied image is encoded into the struct as bits * * @see http://www.xmlrpc.com/metaWeblogApi#metaweblognewmediaobject * @see http://codex.wordpress.org/XML-RPC_wp#wp.uploadFile * * @param xmlrpcmsg XML-RPC Message * 0 blogid (string): Unique identifier of the blog the post will be added to. * Currently ignored in b2evo, in favor of the category. * 1 username (string): Login for a Blogger user who has permission to edit the given * post (either the user who originally created it or an admin of the blog). * 2 password (string): Password for said username. * 3 struct (struct) * - name : filename * - type : mimetype * - bits : base64 encoded file * @return xmlrpcresp XML-RPC Response */ function _wp_mw_newmediaobject($m) { global $Settings, $Plugins, $force_upload_forbiddenext; // CHECK LOGIN: /** * @var User */ if (!($current_User =& xmlrpcs_login($m, 1, 2))) { // Login failed, return (last) error: return xmlrpcs_resperror(); } // GET BLOG: /** * @var Blog */ if (!($Blog =& xmlrpcs_get_Blog($m, 0))) { // Login failed, return (last) error: return xmlrpcs_resperror(); } // CHECK PERMISSION: if (!$current_User->check_perm('files', 'add', false, $Blog->ID)) { // Permission denied return xmlrpcs_resperror(3); // User error 3 } logIO('Permission granted.'); if (!$Settings->get('upload_enabled')) { return xmlrpcs_resperror(2, 'Object upload not allowed'); } $xcontent = $m->getParam(3); // Get the main data - and decode it properly for the image - sorry, binary object logIO('Decoding content...'); $contentstruct = xmlrpc_decode_recurse($xcontent); $data = $contentstruct['bits']; $file_mimetype = isset($contentstruct['type']) ? $contentstruct['type'] : '(none)'; logIO('Received MIME type: ' . $file_mimetype); $overwrite = false; if (isset($contentstruct['overwrite'])) { $overwrite = (bool) $contentstruct['overwrite']; } logIO('Overwrite if exists: ' . ($overwrite ? 'yes' : 'no')); load_funcs('files/model/_file.funcs.php'); $filesize = evo_bytes($data); if (($maxfilesize = $Settings->get('upload_maxkb') * 1024) && $filesize > $maxfilesize) { return xmlrpcs_resperror(4, sprintf(T_('The file is too large: %s but the maximum allowed is %s.'), bytesreadable($filesize, false), bytesreadable($maxfilesize, false))); } logIO('File size is OK: ' . bytesreadable($filesize, false)); $FileRootCache =& get_FileRootCache(); $fm_FileRoot =& $FileRootCache->get_by_type_and_ID('collection', $Blog->ID, true); if (!$fm_FileRoot) { // fileRoot not found: return xmlrpcs_resperror(14, 'File root not found'); } $rf_filepath = $contentstruct['name']; logIO('Received filepath: ' . $rf_filepath); // Split into path + name: $filepath_parts = explode('/', $rf_filepath); $filename = array_pop($filepath_parts); logIO('Original file name: ' . $filename); // Validate and sanitize filename if ($error_filename = process_filename($filename, true)) { return xmlrpcs_resperror(5, $error_filename); } logIO('Sanitized file name: ' . $filename); // Check valid path parts: $rds_subpath = ''; foreach ($filepath_parts as $filepath_part) { if (empty($filepath_part) || $filepath_part == '.') { // self ref not useful continue; } if ($error = validate_dirname($filepath_part)) { // invalid relative path: logIO($error); return xmlrpcs_resperror(6, $error); } $rds_subpath .= $filepath_part . '/'; } logIO('Subpath: ' . $rds_subpath); // Create temporary file and insert contents into it. $tmpfile_name = tempnam(sys_get_temp_dir(), 'fmupload'); if ($tmpfile_name) { if (save_to_file($data, $tmpfile_name, 'wb')) { $image_info = @getimagesize($tmpfile_name); } else { return xmlrpcs_resperror(13, 'Error while writing to temp file.'); } } if (!empty($image_info)) { // This is an image file, let's check mimetype and correct extension if ($image_info['mime'] != $file_mimetype) { // Invalid file type $FiletypeCache =& get_FiletypeCache(); // Get correct file type based on mime type $correct_Filetype = $FiletypeCache->get_by_mimetype($image_info['mime'], false, false); $file_mimetype = $image_info['mime']; // Check if file type is known by us, and if it is allowed for upload. // If we don't know this file type or if it isn't allowed we don't change the extension! The current extension is allowed for sure. if ($correct_Filetype && $correct_Filetype->is_allowed()) { // A FileType with the given mime type exists in database and it is an allowed file type for current User // The "correct" extension is a plausible one, proceed... $correct_extension = array_shift($correct_Filetype->get_extensions()); $path_info = pathinfo($filename); $current_extension = $path_info['extension']; // change file extension to the correct extension, but only if the correct extension is not restricted, this is an extra security check! if (strtolower($current_extension) != strtolower($correct_extension) && !in_array($correct_extension, $force_upload_forbiddenext)) { // change the file extension to the correct extension $old_filename = $filename; $filename = $path_info['filename'] . '.' . $correct_extension; } } } } // Get File object for requested target location: $FileCache =& get_FileCache(); $newFile =& $FileCache->get_by_root_and_path($fm_FileRoot->type, $fm_FileRoot->in_type_ID, trailing_slash($rds_subpath) . $filename, true); if ($newFile->exists()) { if ($overwrite && $newFile->unlink()) { // OK, file deleted // Delete thumb caches from old location: logIO('Old file deleted'); $newFile->rm_cache(); } else { return xmlrpcs_resperror(8, sprintf(T_('The file «%s» already exists.'), $filename)); } } // Trigger plugin event if ($Plugins->trigger_event_first_false('AfterFileUpload', array('File' => &$newFile, 'name' => &$filename, 'type' => &$file_mimetype, 'tmp_name' => &$tmpfile_name, 'size' => &$filesize))) { // Plugin returned 'false'. // Abort upload for this file: @unlink($tmpfile_name); return xmlrpcs_resperror(16, 'File upload aborted by a plugin.'); } if (!mkdir_r($newFile->get_dir())) { // Dir didn't already exist and could not be created return xmlrpcs_resperror(9, 'Error creating sub directories: ' . $newFile->get_rdfs_rel_path()); } if (!@rename($tmpfile_name, $newFile->get_full_path())) { return xmlrpcs_resperror(13, 'Error while writing to file.'); } // chmod the file $newFile->chmod(); // Initializes file properties (type, size, perms...) $newFile->load_properties(); // Load meta data AND MAKE SURE IT IS CREATED IN DB: $newFile->meta == 'unknown'; $newFile->load_meta(true); // Resize and rotate logIO('Running file post-processing (resize and rotate)...'); prepare_uploaded_files(array($newFile)); logIO('Done'); $url = $newFile->get_url(); logIO('URL of new file: ' . $url); $struct = new xmlrpcval(array('file' => new xmlrpcval($filename, 'string'), 'url' => new xmlrpcval($url, 'string'), 'type' => new xmlrpcval($file_mimetype, 'string')), 'struct'); logIO('OK.'); return new xmlrpcresp($struct); }
/** * Fetch remote page * * Attempt to retrieve a remote page using a HTTP GET request, first with * cURL, then fsockopen, then fopen. * * cURL gets skipped, if $max_size_kb is requested, since there appears to be no * method to control this. * {@internal (CURLOPT_READFUNCTION maybe? But it has not been called for me.. seems * to affect sending, not fetching?!)}} * * @todo dh> Should we try remaining methods, if the previous one(s) failed? * @todo Tblue> Also allow HTTP POST. * * @param string URL * @param array Info (by reference) * 'error': holds error message, if any * 'status': HTTP status (e.g. 200 or 404) * 'used_method': Used method ("curl", "fopen", "fsockopen" or null if no method * is available) * @param integer Timeout (default: 15 seconds) * @param integer Maximum size in kB * @return string|false The remote page as a string; false in case of error */ function fetch_remote_page($url, &$info, $timeout = NULL, $max_size_kb = NULL) { global $outgoing_proxy_hostname, $outgoing_proxy_port, $outgoing_proxy_username, $outgoing_proxy_password; $info = array('error' => '', 'status' => NULL, 'mimetype' => NULL, 'used_method' => NULL); if (!isset($timeout)) { $timeout = 15; } if (extension_loaded('curl') && !$max_size_kb) { // CURL: $info['used_method'] = 'curl'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // Set proxy: if (!empty($outgoing_proxy_hostname)) { curl_setopt($ch, CURLOPT_PROXY, $outgoing_proxy_hostname); curl_setopt($ch, CURLOPT_PROXYPORT, $outgoing_proxy_port); curl_setopt($ch, CURLOPT_PROXYUSERPWD, $outgoing_proxy_username . ':' . $outgoing_proxy_password); } @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // made silent due to possible errors with safe_mode/open_basedir(?) curl_setopt($ch, CURLOPT_MAXREDIRS, 3); $r = curl_exec($ch); $info['mimetype'] = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $info['status'] = curl_getinfo($ch, CURLINFO_HTTP_CODE); $info['error'] = curl_error($ch); if ($errno = curl_errno($ch)) { $info['error'] .= ' (#' . $errno . ')'; } curl_close($ch); return $r; } if (function_exists('fsockopen')) { // FSOCKOPEN: $info['used_method'] = 'fsockopen'; if (($url_parsed = @parse_url($url)) === false || !isset($url_parsed['host'])) { $info['error'] = NT_('Could not parse URL'); return false; } $host = $url_parsed['host']; $port = empty($url_parsed['port']) ? 80 : $url_parsed['port']; $path = empty($url_parsed['path']) ? '/' : $url_parsed['path']; if (!empty($url_parsed['query'])) { $path .= '?' . $url_parsed['query']; } $out = 'GET ' . $path . ' HTTP/1.1' . "\r\n"; $out .= 'Host: ' . $host; if (!empty($url_parsed['port'])) { // we don't want to add :80 if not specified. remote end may not resolve it. (e-g b2evo multiblog does not) $out .= ':' . $port; } $out .= "\r\n" . 'Connection: Close' . "\r\n\r\n"; $fp = @fsockopen($host, $port, $errno, $errstr, $timeout); if (!$fp) { $info['error'] = $errstr . ' (#' . $errno . ')'; return false; } // Send request: fwrite($fp, $out); // Set timeout for data: if (function_exists('stream_set_timeout')) { stream_set_timeout($fp, $timeout); // PHP 4.3.0 } else { socket_set_timeout($fp, $timeout); // PHP 4 } // Read response: $r = ''; // First line: $s = fgets($fp); if (!preg_match('~^HTTP/\\d+\\.\\d+ (\\d+)~', $s, $match)) { $info['error'] = NT_('Invalid response.'); fclose($fp); return false; } while (!feof($fp)) { $r .= fgets($fp); if ($max_size_kb && evo_bytes($r) >= $max_size_kb * 1024) { $info['error'] = NT_(sprintf('Maximum size of %d kB reached.', $max_size_kb)); return false; } } fclose($fp); if (($pos = strpos($r, "\r\n\r\n")) === false) { $info['error'] = NT_('Could not locate end of headers'); return false; } // Remember headers to extract info at the end $headers = explode("\r\n", substr($r, 0, $pos)); $info['status'] = $match[1]; $r = substr($r, $pos + 4); } elseif (ini_get('allow_url_fopen')) { // URL FOPEN: $info['used_method'] = 'fopen'; $fp = @fopen($url, 'r'); if (!$fp) { if (isset($http_response_header) && ($code = _http_wrapper_last_status($http_response_header)) !== false) { // fopen() returned false because it got a bad HTTP code: $info['error'] = NT_('Invalid response'); $info['status'] = $code; return ''; } $info['error'] = NT_('fopen() failed'); return false; } else { if (!isset($http_response_header) || ($code = _http_wrapper_last_status($http_response_header)) === false) { $info['error'] = NT_('Invalid response'); return false; } else { // Used to get info at the end $headers = $http_response_header; // Retrieve contents $r = ''; while (!feof($fp)) { $r .= fgets($fp); if ($max_size_kb && evo_bytes($r) >= $max_size_kb * 1024) { $info['error'] = NT_(sprintf('Maximum size of %d kB reached.', $max_size_kb)); return false; } } $info['status'] = $code; } } fclose($fp); } // Extract mimetype info from the headers (for fsockopen/fopen) if (isset($r)) { foreach ($headers as $header) { $header = strtolower($header); if (substr($header, 0, 13) == 'content-type:') { $info['mimetype'] = trim(substr($header, 13)); break; // only looking for mimetype } } return $r; } // All failed: $info['error'] = NT_('No method available to access URL!'); return false; }