File indexing completed on 2025-01-19 05:21:07
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_File_Transfer 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_File_Transfer_Adapter_Abstract 0024 */ 0025 // require_once 'Zend/File/Transfer/Adapter/Abstract.php'; 0026 0027 /** 0028 * File transfer adapter class for the HTTP protocol 0029 * 0030 * @category Zend 0031 * @package Zend_File_Transfer 0032 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0033 * @license http://framework.zend.com/license/new-bsd New BSD License 0034 */ 0035 class Zend_File_Transfer_Adapter_Http extends Zend_File_Transfer_Adapter_Abstract 0036 { 0037 protected static $_callbackApc = 'apc_fetch'; 0038 protected static $_callbackUploadProgress = 'uploadprogress_get_info'; 0039 0040 /** 0041 * Constructor for Http File Transfers 0042 * 0043 * @param array $options OPTIONAL Options to set 0044 */ 0045 public function __construct($options = array()) 0046 { 0047 if (ini_get('file_uploads') == false) { 0048 // require_once 'Zend/File/Transfer/Exception.php'; 0049 throw new Zend_File_Transfer_Exception('File uploads are not allowed in your php config!'); 0050 } 0051 0052 $this->setOptions($options); 0053 $this->_prepareFiles(); 0054 $this->addValidator('Upload', false, $this->_files); 0055 } 0056 0057 /** 0058 * Sets a validator for the class, erasing all previous set 0059 * 0060 * @param string|array $validator Validator to set 0061 * @param string|array $files Files to limit this validator to 0062 * @return Zend_File_Transfer_Adapter 0063 */ 0064 public function setValidators(array $validators, $files = null) 0065 { 0066 $this->clearValidators(); 0067 return $this->addValidators($validators, $files); 0068 } 0069 0070 /** 0071 * Remove an individual validator 0072 * 0073 * @param string $name 0074 * @return Zend_File_Transfer_Adapter_Abstract 0075 */ 0076 public function removeValidator($name) 0077 { 0078 if ($name == 'Upload') { 0079 return $this; 0080 } 0081 0082 return parent::removeValidator($name); 0083 } 0084 0085 /** 0086 * Remove an individual validator 0087 * 0088 * @param string $name 0089 * @return Zend_File_Transfer_Adapter_Abstract 0090 */ 0091 public function clearValidators() 0092 { 0093 parent::clearValidators(); 0094 $this->addValidator('Upload', false, $this->_files); 0095 0096 return $this; 0097 } 0098 0099 /** 0100 * Send the file to the client (Download) 0101 * 0102 * @param string|array $options Options for the file(s) to send 0103 * @return void 0104 * @throws Zend_File_Transfer_Exception Not implemented 0105 */ 0106 public function send($options = null) 0107 { 0108 // require_once 'Zend/File/Transfer/Exception.php'; 0109 throw new Zend_File_Transfer_Exception('Method not implemented'); 0110 } 0111 0112 /** 0113 * Checks if the files are valid 0114 * 0115 * @param string|array $files (Optional) Files to check 0116 * @return boolean True if all checks are valid 0117 */ 0118 public function isValid($files = null) 0119 { 0120 // Workaround for WebServer not conforming HTTP and omitting CONTENT_LENGTH 0121 $content = 0; 0122 if (isset($_SERVER['CONTENT_LENGTH'])) { 0123 $content = $_SERVER['CONTENT_LENGTH']; 0124 } else if (!empty($_POST)) { 0125 $content = serialize($_POST); 0126 } 0127 0128 // Workaround for a PHP error returning empty $_FILES when form data exceeds php settings 0129 if (empty($this->_files) && ($content > 0)) { 0130 if (is_array($files)) { 0131 if (0 === count($files)) { 0132 return false; 0133 } 0134 0135 $files = current($files); 0136 } 0137 0138 $temp = array($files => array( 0139 'name' => $files, 0140 'error' => 1)); 0141 $validator = $this->_validators['Zend_Validate_File_Upload']; 0142 $validator->setFiles($temp) 0143 ->isValid($files, null); 0144 $this->_messages += $validator->getMessages(); 0145 return false; 0146 } 0147 0148 return parent::isValid($files); 0149 } 0150 0151 /** 0152 * Receive the file from the client (Upload) 0153 * 0154 * @param string|array $files (Optional) Files to receive 0155 * @return bool 0156 */ 0157 public function receive($files = null) 0158 { 0159 if (!$this->isValid($files)) { 0160 return false; 0161 } 0162 0163 $check = $this->_getFiles($files); 0164 foreach ($check as $file => $content) { 0165 if (!$content['received']) { 0166 $directory = ''; 0167 $destination = $this->getDestination($file); 0168 if ($destination !== null) { 0169 $directory = $destination . DIRECTORY_SEPARATOR; 0170 } 0171 0172 $filename = $directory . $content['name']; 0173 $rename = $this->getFilter('Rename'); 0174 if ($rename !== null) { 0175 $tmp = $rename->getNewName($content['tmp_name']); 0176 if ($tmp != $content['tmp_name']) { 0177 $filename = $tmp; 0178 } 0179 0180 if (dirname($filename) == '.') { 0181 $filename = $directory . $filename; 0182 } 0183 0184 $key = array_search(get_class($rename), $this->_files[$file]['filters']); 0185 unset($this->_files[$file]['filters'][$key]); 0186 } 0187 0188 // Should never return false when it's tested by the upload validator 0189 if (!move_uploaded_file($content['tmp_name'], $filename)) { 0190 if ($content['options']['ignoreNoFile']) { 0191 $this->_files[$file]['received'] = true; 0192 $this->_files[$file]['filtered'] = true; 0193 continue; 0194 } 0195 0196 $this->_files[$file]['received'] = false; 0197 return false; 0198 } 0199 0200 if ($rename !== null) { 0201 $this->_files[$file]['destination'] = dirname($filename); 0202 $this->_files[$file]['name'] = basename($filename); 0203 } 0204 0205 $this->_files[$file]['tmp_name'] = $filename; 0206 $this->_files[$file]['received'] = true; 0207 } 0208 0209 if (!$content['filtered']) { 0210 if (!$this->_filter($file)) { 0211 $this->_files[$file]['filtered'] = false; 0212 return false; 0213 } 0214 0215 $this->_files[$file]['filtered'] = true; 0216 } 0217 } 0218 0219 return true; 0220 } 0221 0222 /** 0223 * Checks if the file was already sent 0224 * 0225 * @param string|array $file Files to check 0226 * @return bool 0227 * @throws Zend_File_Transfer_Exception Not implemented 0228 */ 0229 public function isSent($files = null) 0230 { 0231 // require_once 'Zend/File/Transfer/Exception.php'; 0232 throw new Zend_File_Transfer_Exception('Method not implemented'); 0233 } 0234 0235 /** 0236 * Checks if the file was already received 0237 * 0238 * @param string|array $files (Optional) Files to check 0239 * @return bool 0240 */ 0241 public function isReceived($files = null) 0242 { 0243 $files = $this->_getFiles($files, false, true); 0244 if (empty($files)) { 0245 return false; 0246 } 0247 0248 foreach ($files as $content) { 0249 if ($content['received'] !== true) { 0250 return false; 0251 } 0252 } 0253 0254 return true; 0255 } 0256 0257 /** 0258 * Checks if the file was already filtered 0259 * 0260 * @param string|array $files (Optional) Files to check 0261 * @return bool 0262 */ 0263 public function isFiltered($files = null) 0264 { 0265 $files = $this->_getFiles($files, false, true); 0266 if (empty($files)) { 0267 return false; 0268 } 0269 0270 foreach ($files as $content) { 0271 if ($content['filtered'] !== true) { 0272 return false; 0273 } 0274 } 0275 0276 return true; 0277 } 0278 0279 /** 0280 * Has a file been uploaded ? 0281 * 0282 * @param array|string|null $file 0283 * @return bool 0284 */ 0285 public function isUploaded($files = null) 0286 { 0287 $files = $this->_getFiles($files, false, true); 0288 if (empty($files)) { 0289 return false; 0290 } 0291 0292 foreach ($files as $file) { 0293 if (empty($file['name'])) { 0294 return false; 0295 } 0296 } 0297 0298 return true; 0299 } 0300 0301 /** 0302 * Returns the actual progress of file up-/downloads 0303 * 0304 * @param string $id The upload to get the progress for 0305 * @return array|null 0306 */ 0307 public static function getProgress($id = null) 0308 { 0309 if (!function_exists('apc_fetch') and !function_exists('uploadprogress_get_info')) { 0310 // require_once 'Zend/File/Transfer/Exception.php'; 0311 throw new Zend_File_Transfer_Exception('Neither APC nor uploadprogress extension installed'); 0312 } 0313 0314 $session = 'Zend_File_Transfer_Adapter_Http_ProgressBar'; 0315 $status = array( 0316 'total' => 0, 0317 'current' => 0, 0318 'rate' => 0, 0319 'message' => '', 0320 'done' => false 0321 ); 0322 0323 if (is_array($id)) { 0324 if (isset($id['progress'])) { 0325 $adapter = $id['progress']; 0326 } 0327 0328 if (isset($id['session'])) { 0329 $session = $id['session']; 0330 } 0331 0332 if (isset($id['id'])) { 0333 $id = $id['id']; 0334 } else { 0335 unset($id); 0336 } 0337 } 0338 0339 if (!empty($id) && (($id instanceof Zend_ProgressBar_Adapter) || ($id instanceof Zend_ProgressBar))) { 0340 $adapter = $id; 0341 unset($id); 0342 } 0343 0344 if (empty($id)) { 0345 if (!isset($_GET['progress_key'])) { 0346 $status['message'] = 'No upload in progress'; 0347 $status['done'] = true; 0348 } else { 0349 $id = $_GET['progress_key']; 0350 } 0351 } 0352 0353 if (!empty($id)) { 0354 if (self::isApcAvailable()) { 0355 0356 $call = call_user_func(self::$_callbackApc, ini_get('apc.rfc1867_prefix') . $id); 0357 if (is_array($call)) { 0358 $status = $call + $status; 0359 } 0360 } else if (self::isUploadProgressAvailable()) { 0361 $call = call_user_func(self::$_callbackUploadProgress, $id); 0362 if (is_array($call)) { 0363 $status = $call + $status; 0364 $status['total'] = $status['bytes_total']; 0365 $status['current'] = $status['bytes_uploaded']; 0366 $status['rate'] = $status['speed_average']; 0367 if ($status['total'] == $status['current']) { 0368 $status['done'] = true; 0369 } 0370 } 0371 } 0372 0373 if (!is_array($call)) { 0374 $status['done'] = true; 0375 $status['message'] = 'Failure while retrieving the upload progress'; 0376 } else if (!empty($status['cancel_upload'])) { 0377 $status['done'] = true; 0378 $status['message'] = 'The upload has been canceled'; 0379 } else { 0380 $status['message'] = self::_toByteString($status['current']) . " - " . self::_toByteString($status['total']); 0381 } 0382 0383 $status['id'] = $id; 0384 } 0385 0386 if (isset($adapter) && isset($status['id'])) { 0387 if ($adapter instanceof Zend_ProgressBar_Adapter) { 0388 // require_once 'Zend/ProgressBar.php'; 0389 $adapter = new Zend_ProgressBar($adapter, 0, $status['total'], $session); 0390 } 0391 0392 if (!($adapter instanceof Zend_ProgressBar)) { 0393 // require_once 'Zend/File/Transfer/Exception.php'; 0394 throw new Zend_File_Transfer_Exception('Unknown Adapter given'); 0395 } 0396 0397 if ($status['done']) { 0398 $adapter->finish(); 0399 } else { 0400 $adapter->update($status['current'], $status['message']); 0401 } 0402 0403 $status['progress'] = $adapter; 0404 } 0405 0406 return $status; 0407 } 0408 0409 /** 0410 * Checks the APC extension for progress information 0411 * 0412 * @return boolean 0413 */ 0414 public static function isApcAvailable() 0415 { 0416 return (bool) ini_get('apc.enabled') && (bool) ini_get('apc.rfc1867') && is_callable(self::$_callbackApc); 0417 } 0418 0419 /** 0420 * Checks the UploadProgress extension for progress information 0421 * 0422 * @return boolean 0423 */ 0424 public static function isUploadProgressAvailable() 0425 { 0426 return is_callable(self::$_callbackUploadProgress); 0427 } 0428 0429 /** 0430 * Prepare the $_FILES array to match the internal syntax of one file per entry 0431 * 0432 * @param array $files 0433 * @return array 0434 */ 0435 protected function _prepareFiles() 0436 { 0437 $this->_files = array(); 0438 foreach ($_FILES as $form => $content) { 0439 if (is_array($content['name'])) { 0440 foreach ($content as $param => $file) { 0441 foreach ($file as $number => $target) { 0442 $this->_files[$form . '_' . $number . '_'][$param] = $target; 0443 $this->_files[$form]['multifiles'][$number] = $form . '_' . $number . '_'; 0444 } 0445 } 0446 0447 $this->_files[$form]['name'] = $form; 0448 foreach($this->_files[$form]['multifiles'] as $key => $value) { 0449 $this->_files[$value]['options'] = $this->_options; 0450 $this->_files[$value]['validated'] = false; 0451 $this->_files[$value]['received'] = false; 0452 $this->_files[$value]['filtered'] = false; 0453 0454 $mimetype = $this->_detectMimeType($this->_files[$value]); 0455 $this->_files[$value]['type'] = $mimetype; 0456 0457 $filesize = $this->_detectFileSize($this->_files[$value]); 0458 $this->_files[$value]['size'] = $filesize; 0459 0460 if ($this->_options['detectInfos']) { 0461 $_FILES[$form]['type'][$key] = $mimetype; 0462 $_FILES[$form]['size'][$key] = $filesize; 0463 } 0464 } 0465 } else { 0466 $this->_files[$form] = $content; 0467 $this->_files[$form]['options'] = $this->_options; 0468 $this->_files[$form]['validated'] = false; 0469 $this->_files[$form]['received'] = false; 0470 $this->_files[$form]['filtered'] = false; 0471 0472 $mimetype = $this->_detectMimeType($this->_files[$form]); 0473 $this->_files[$form]['type'] = $mimetype; 0474 0475 $filesize = $this->_detectFileSize($this->_files[$form]); 0476 $this->_files[$form]['size'] = $filesize; 0477 0478 if ($this->_options['detectInfos']) { 0479 $_FILES[$form]['type'] = $mimetype; 0480 $_FILES[$form]['size'] = $filesize; 0481 } 0482 } 0483 } 0484 0485 return $this; 0486 } 0487 }