public function send404ImageNotFound()
 {
     $this->mSpecial->getOutput()->disable();
     # No HTML output
     StreamFile::prepareForStream(null, null, null, true);
     # send 404 Not Found
 }
Esempio n. 2
0
 /**
  * @see FileBackendStore::doStoreInternal()
  * @return Status
  */
 protected function doStoreInternal(array $params)
 {
     $status = Status::newGood();
     list($dstCont, $dstRel) = $this->resolveStoragePathReal($params['dst']);
     if ($dstRel === null) {
         $status->fatal('backend-fail-invalidpath', $params['dst']);
         return $status;
     }
     // (a) Check the destination container and object
     try {
         $dContObj = $this->getContainer($dstCont);
     } catch (NoSuchContainerException $e) {
         $status->fatal('backend-fail-copy', $params['src'], $params['dst']);
         return $status;
     } catch (CloudFilesException $e) {
         // some other exception?
         $this->handleException($e, $status, __METHOD__, $params);
         return $status;
     }
     // (b) Get a SHA-1 hash of the object
     wfSuppressWarnings();
     $sha1Hash = sha1_file($params['src']);
     wfRestoreWarnings();
     if ($sha1Hash === false) {
         // source doesn't exist?
         $status->fatal('backend-fail-copy', $params['src'], $params['dst']);
         return $status;
     }
     $sha1Hash = wfBaseConvert($sha1Hash, 16, 36, 31);
     // (c) Actually store the object
     try {
         // Create a fresh CF_Object with no fields preloaded.
         // We don't want to preserve headers, metadata, and such.
         $obj = new CF_Object($dContObj, $dstRel, false, false);
         // skip HEAD
         $obj->setMetadataValues(array('Sha1base36' => $sha1Hash));
         // The MD5 here will be checked within Swift against its own MD5.
         $obj->set_etag(md5_file($params['src']));
         // Use the same content type as StreamFile for security
         $obj->content_type = StreamFile::contentTypeFromPath($params['dst']);
         if (!strlen($obj->content_type)) {
             // special case
             $obj->content_type = 'unknown/unknown';
         }
         // Set any other custom headers if requested
         if (isset($params['headers'])) {
             $obj->headers += $this->sanitizeHdrs($params['headers']);
         }
         if (!empty($params['async'])) {
             // deferred
             wfSuppressWarnings();
             $fp = fopen($params['src'], 'rb');
             wfRestoreWarnings();
             if (!$fp) {
                 $status->fatal('backend-fail-copy', $params['src'], $params['dst']);
             } else {
                 $op = $obj->write_async($fp, filesize($params['src']), true);
                 $status->value = new SwiftFileOpHandle($this, $params, 'Store', $op);
                 $status->value->resourcesToClose[] = $fp;
                 $status->value->affectedObjects[] = $obj;
             }
         } else {
             // actually write the object in Swift
             $obj->load_from_filename($params['src'], true);
             // calls $obj->write()
             $this->purgeCDNCache(array($obj));
         }
     } catch (CDNNotEnabledException $e) {
         // CDN not enabled; nothing to see here
     } catch (BadContentTypeException $e) {
         $status->fatal('backend-fail-contenttype', $params['dst']);
     } catch (IOException $e) {
         $status->fatal('backend-fail-copy', $params['src'], $params['dst']);
     } catch (CloudFilesException $e) {
         // some other exception?
         $this->handleException($e, $status, __METHOD__, $params);
     }
     return $status;
 }
Esempio n. 3
0
 /**
  * @see FileBackendStore::doCreateInternal()
  */
 protected function doCreateInternal(array $params)
 {
     $status = Status::newGood();
     list($dstCont, $dstRel) = $this->resolveStoragePathReal($params['dst']);
     if ($dstRel === null) {
         $status->fatal('backend-fail-invalidpath', $params['dst']);
         return $status;
     }
     // (a) Check the destination container and object
     try {
         unset($this->objCache[$params['dst']]);
         $dContObj = $this->getContainer($dstCont);
         if (empty($params['overwrite']) && $this->fileExists(array('src' => $params['dst'], 'latest' => 1))) {
             $status->fatal('backend-fail-alreadyexists', $params['dst']);
             return $status;
         }
     } catch (NoSuchContainerException $e) {
         $status->fatal('backend-fail-create', $params['dst']);
         $this->logException($e, __METHOD__, $params);
         return $status;
     } catch (InvalidResponseException $e) {
         $status->fatal('backend-fail-connect', $this->name);
         $this->logException($e, __METHOD__, $params);
         return $status;
     } catch (Exception $e) {
         // some other exception?
         $status->fatal('backend-fail-internal', $this->name);
         $this->logException($e, __METHOD__, $params);
         return $status;
     }
     // (b) Get a SHA-1 hash of the object
     $sha1Hash = wfBaseConvert(sha1($params['content']), 16, 36, 31);
     // (c) Actually create the object
     try {
         // Create a fresh CF_Object with no fields preloaded.
         // We don't want to preserve headers, metadata, and such.
         $obj = new CF_Object($dContObj, $dstRel, false, false);
         // skip HEAD
         // Note: metadata keys stored as [Upper case char][[Lower case char]...]
         $obj->metadata = array('Sha1base36' => $sha1Hash);
         // Manually set the ETag (https://github.com/rackspace/php-cloudfiles/issues/59).
         // The MD5 here will be checked within Swift against its own MD5.
         $obj->set_etag(md5($params['content']));
         // Use the same content type as StreamFile for security
         $obj->content_type = StreamFile::contentTypeFromPath($params['dst']);
         // Actually write the object in Swift
         $obj->write($params['content']);
     } catch (BadContentTypeException $e) {
         $status->fatal('backend-fail-contenttype', $params['dst']);
         $this->logException($e, __METHOD__, $params);
     } catch (InvalidResponseException $e) {
         $status->fatal('backend-fail-connect', $this->name);
         $this->logException($e, __METHOD__, $params);
     } catch (Exception $e) {
         // some other exception?
         $status->fatal('backend-fail-internal', $this->name);
         $this->logException($e, __METHOD__, $params);
     }
     return $status;
 }
 public function streamFile(array $params)
 {
     // The stream methods use the file extension to determine the
     // Content-Type (as MediaWiki should already validate it on upload).
     // The translated SHA1 path has no extension, so this needs to use
     // the untranslated path extension.
     $type = StreamFile::contentTypeFromPath($params['src']);
     if ($type && $type != 'unknown/unknown') {
         $params['headers'][] = "Content-type: {$type}";
     }
     return $this->translateSrcParams(__FUNCTION__, $params);
 }
Esempio n. 5
0
 /**
  * @see FileBackend::streamFile()
  * @return Status
  */
 public final function streamFile(array $params)
 {
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-' . $this->name);
     $status = Status::newGood();
     $info = $this->getFileStat($params);
     if (!$info) {
         // let StreamFile handle the 404
         $status->fatal('backend-fail-notexists', $params['src']);
     }
     // Set output buffer and HTTP headers for stream
     $extraHeaders = isset($params['headers']) ? $params['headers'] : array();
     $res = StreamFile::prepareForStream($params['src'], $info, $extraHeaders);
     if ($res == StreamFile::NOT_MODIFIED) {
         // do nothing; client cache is up to date
     } elseif ($res == StreamFile::READY_STREAM) {
         wfProfileIn(__METHOD__ . '-send');
         wfProfileIn(__METHOD__ . '-send-' . $this->name);
         $status = $this->doStreamFile($params);
         wfProfileOut(__METHOD__ . '-send-' . $this->name);
         wfProfileOut(__METHOD__ . '-send');
     } else {
         $status->fatal('backend-fail-stream', $params['src']);
     }
     wfProfileOut(__METHOD__ . '-' . $this->name);
     wfProfileOut(__METHOD__);
     return $status;
 }
 /**
  * Stream the file if there were no errors
  *
  * @param array $headers Additional HTTP headers to send on success
  * @return Status
  * @since 1.27
  */
 public function streamFileWithStatus($headers = [])
 {
     if (!$this->path) {
         return Status::newFatal('backend-fail-stream', '<no path>');
     } elseif (FileBackend::isStoragePath($this->path)) {
         $be = $this->file->getRepo()->getBackend();
         return $be->streamFile(['src' => $this->path, 'headers' => $headers]);
     } else {
         // FS-file
         $success = StreamFile::stream($this->getLocalCopyPath(), $headers);
         return $success ? Status::newGood() : Status::newFatal('backend-fail-stream', $this->path);
     }
 }
	/**
	 * Stream the file if there were no errors
	 *
	 * @param array $headers Additional HTTP headers to send on success
	 * @return Bool success
	 */
	public function streamFile( $headers = array() ) {
		if ( !$this->path ) {
			return false;
		} elseif ( FileBackend::isStoragePath( $this->path ) ) {
			$be = $this->file->getRepo()->getBackend();
			return $be->streamFile( array( 'src' => $this->path, 'headers' => $headers ) )->isOK();
		} else { // FS-file
			return StreamFile::stream( $this->getLocalCopyPath(), $headers );
		}
	}
/**
 * Stream a file to the browser. Back-compat alias for StreamFile::stream()
 * @deprecated since 1.19
 */
function wfStreamFile($fname, $headers = array())
{
    wfDeprecated(__FUNCTION__, '1.19');
    StreamFile::stream($fname, $headers);
}
Esempio n. 9
0
 /**
  * Stream the file if there were no errors
  *
  * @param $headers Array Additional HTTP headers to send on success
  * @return Bool success
  */
 public function streamFile($headers = array())
 {
     return $this->path && StreamFile::stream($this->getLocalCopyPath(), $headers);
 }
 public final function streamFile(array $params)
 {
     $ps = Profiler::instance()->scopedProfileIn(__METHOD__ . "-{$this->name}");
     $status = Status::newGood();
     $info = $this->getFileStat($params);
     if (!$info) {
         // let StreamFile handle the 404
         $status->fatal('backend-fail-notexists', $params['src']);
     }
     // Set output buffer and HTTP headers for stream
     $extraHeaders = isset($params['headers']) ? $params['headers'] : array();
     $res = StreamFile::prepareForStream($params['src'], $info, $extraHeaders);
     if ($res == StreamFile::NOT_MODIFIED) {
         // do nothing; client cache is up to date
     } elseif ($res == StreamFile::READY_STREAM) {
         $status = $this->doStreamFile($params);
         if (!$status->isOK()) {
             // Per bug 41113, nasty things can happen if bad cache entries get
             // stuck in cache. It's also possible that this error can come up
             // with simple race conditions. Clear out the stat cache to be safe.
             $this->clearCache(array($params['src']));
             $this->deleteFileCache($params['src']);
             trigger_error("Bad stat cache or race condition for file {$params['src']}.");
         }
     } else {
         $status->fatal('backend-fail-stream', $params['src']);
     }
     return $status;
 }
	/**
	 *
	 */
	protected function streamThumbnail() {
		global $wgVipsThumbnailerHost, $wgVipsTestExpiry;

		$request = $this->getRequest();

		# Validate title and file existance
		$title = Title::makeTitleSafe( NS_FILE, $request->getText( 'thumb' ) );
		if ( is_null( $title ) ) {
			$this->streamError( 404, "VipsScaler: invalid title\n" );
			return;
		}
		$file = wfFindFile( $title );
		if ( !$file || !$file->exists() ) {
			$this->streamError( 404, "VipsScaler: file not found\n" );
			return;
		}

		# Check if vips can handle this file
		if ( VipsScaler::getVipsHandler( $file ) === false ) {
			$this->streamError( 500, "VipsScaler: VIPS cannot handle this file type\n" );
			return;
		}

		# Validate param string
		$handler = $file->getHandler();
		$params = array( 'width' => $request->getInt( 'width' ) );
		if ( !$handler->normaliseParams( $file, $params ) ) {
			$this->streamError( 500, "VipsScaler: invalid parameters\n" );
			return;
		}

		# Get the thumbnail
		if ( is_null( $wgVipsThumbnailerHost ) || $request->getBool( 'noproxy' ) ) {
			# No remote scaler, need to do it ourselves.
			# Emulate the BitmapHandlerTransform hook

			$dstPath = VipsCommand::makeTemp( $file->getExtension() );
			$dstUrl = '';
			wfDebug( __METHOD__ . ": Creating vips thumbnail at $dstPath\n" );

			$scalerParams = array(
				# The size to which the image will be resized
				'physicalWidth' => $params['physicalWidth'],
				'physicalHeight' => $params['physicalHeight'],
				'physicalDimensions' => "{$params['physicalWidth']}x{$params['physicalHeight']}",
				# The size of the image on the page
				'clientWidth' => $params['width'],
				'clientHeight' => $params['height'],
				# Comment as will be added to the EXIF of the thumbnail
				'comment' => isset( $params['descriptionUrl'] ) ?
					"File source: {$params['descriptionUrl']}" : '',
				# Properties of the original image
				'srcWidth' => $file->getWidth(),
				'srcHeight' => $file->getHeight(),
				'mimeType' => $file->getMimeType(),
				'srcPath' => $file->getPath(),
				'dstPath' => $dstPath,
				'dstUrl' => $dstUrl,
			);

			$options = array();
			if ( $request->getBool( 'bilinear' ) ) {
				$options['bilinear'] = true;
				wfDebug( __METHOD__ . ": using bilinear scaling\n" );
			}
			if ( $request->getVal( 'sharpen' ) && $request->getVal( 'sharpen' ) < 5 ) {
				# Limit sharpen sigma to 5, otherwise we have to write huge convolution matrices
				$options['sharpen'] = array( 'sigma' => floatval( $request->getVal( 'sharpen' ) ) );
				wfDebug( __METHOD__ . ": sharpening with radius {$options['sharpen']}\n" );
			}

			# Call the hook
			$mto = null;
			VipsScaler::doTransform( $handler, $file, $scalerParams, $options, $mto );
			if ( $mto && !$mto->isError() ) {
				wfDebug( __METHOD__ . ": streaming thumbnail...\n" );
				$this->getOutput()->disable();
				StreamFile::stream( $dstPath, array(
					"Cache-Control: public, max-age=$wgVipsTestExpiry, s-maxage=$wgVipsTestExpiry",
					'Expires: ' . gmdate( 'r ', time() + $wgVipsTestExpiry )
				) );
			} else {
				$this->streamError( 500, $mto->getHtmlMsg() );
			}

			# Cleanup the temporary file
			wfSuppressWarnings();
			unlink( $dstPath );
			wfRestoreWarnings();

		} else {
			# Request the thumbnail at a remote scaler
			$url = wfExpandUrl( $request->getRequestURL(), PROTO_INTERNAL );
			$url = wfAppendQuery( $url, array( 'noproxy' => '1' ) );
			wfDebug( __METHOD__ . ": Getting vips thumb from remote url $url\n" );

			$bits = IP::splitHostAndPort( $wgVipsThumbnailerHost );
			if ( !$bits ) {
				throw new MWException( __METHOD__.': $wgVipsThumbnailerHost is not set to a valid host' );
			}
			list( $host, $port ) = $bits;
			if ( $port === false ) {
				$port = 80;
			}
			$proxy = IP::combineHostAndPort( $host, $port );

			$options = array(
				'method' => 'GET',
				'proxy' => $proxy,
			);

			$req = MWHttpRequest::factory( $url, $options );
			$status = $req->execute();
			if ( $status->isOk() ) {
				# Disable output and stream the file
				$this->getOutput()->disable();
				wfResetOutputBuffers();
				header( 'Content-Type: ' . $file->getMimeType() );
				header( 'Content-Length: ' . strlen( $req->getContent() ) );
				header( "Cache-Control: public, max-age=$wgVipsTestExpiry, s-maxage=$wgVipsTestExpiry" );
				header( 'Expires: ' . gmdate( 'r ', time() + $wgVipsTestExpiry ) );
				print $req->getContent();
			} elseif ( $status->hasMessage( 'http-bad-status' ) ) {
				$this->streamError( 500, $req->getContent() );
				return;
			} else {
				global $wgOut;
				$this->streamError( 500, $wgOut->parse( $status->getWikiText() ) );
				return;
			}
		}
	}
Esempio n. 12
0
 /**
  * @return bool
  *
  * @throws \MWException
  */
 public function showImage()
 {
     $error = null;
     $this->wg->Out->disable();
     $info = $this->retrieveCaptcha();
     if ($info) {
         $info['viewed'] = wfTimestamp();
         $this->storeCaptcha($info);
         $salt = $info['salt'];
         $hash = $info['hash'];
         $file = $this->imagePath($salt, $hash);
         if (file_exists($file)) {
             header("Cache-Control: private, s-maxage=0, max-age=3600");
             \StreamFile::stream($file);
             return true;
         } else {
             $error = 'File ' . $file . ' does not exist';
         }
     } else {
         $error = 'Info is empty';
     }
     wfHttpError(404, '404 not found', 'Requested non-existing captcha image');
     $this->log('Captcha returned 404: ' . $error);
     return false;
 }