48 private $httpRequestFactory;
60 private const MAX_SERVE_BYTES = 1048576;
70 parent::__construct(
'UploadStash',
'upload' );
72 $this->httpRequestFactory = $httpRequestFactory;
89 $this->stash = $this->localRepo->getUploadStash( $this->
getUser() );
92 if ( $subPage ===
null || $subPage ===
'' ) {
111 $params = $this->parseKey( $key );
112 if ( $params[
'type'] ===
'thumb' ) {
113 $this->outputThumbFromStash( $params[
'file'], $params[
'params'] );
115 $this->outputLocalFile( $params[
'file'] );
120 $message = $e->getMessage();
121 }
catch ( Exception $e ) {
123 $message = $e->getMessage();
138 private function parseKey( $key ) {
139 $type = strtok( $key,
'/' );
141 if (
$type !==
'file' &&
$type !==
'thumb' ) {
143 $this->
msg(
'uploadstash-bad-path-unknown-type',
$type )
146 $fileName = strtok(
'/' );
147 $thumbPart = strtok(
'/' );
148 $file = $this->stash->getFile( $fileName );
149 if (
$type ===
'thumb' ) {
150 $srcNamePos = strrpos( $thumbPart, $fileName );
151 if ( $srcNamePos ===
false || $srcNamePos < 1 ) {
153 $this->
msg(
'uploadstash-bad-path-unrecognized-thumb-name' )
156 $paramString = substr( $thumbPart, 0, $srcNamePos - 1 );
158 $handler =
$file->getHandler();
160 $params = $handler->parseParamString( $paramString );
162 return [
'file' =>
$file,
'type' =>
$type,
'params' => $params ];
165 $this->
msg(
'uploadstash-bad-path-no-handler', $file->getMimeType(),
$file->getPath() )
179 private function outputThumbFromStash(
$file, $params ) {
186 if (
$file->getRepo()->getThumbProxyUrl()
187 || $this->getConfig()->get( MainConfigNames::UploadStashScalerBaseUrl )
189 $this->outputRemoteScaledThumb(
$file, $params, $flags );
191 $this->outputLocallyScaledThumb(
$file, $params, $flags );
203 private function outputLocallyScaledThumb(
$file, $params, $flags ) {
209 $thumbnailImage =
$file->transform( $params, $flags );
210 if ( !$thumbnailImage ) {
212 $this->
msg(
'uploadstash-file-not-found-no-thumb' )
217 if ( !$thumbnailImage->getStoragePath() ) {
219 $this->
msg(
'uploadstash-file-not-found-no-local-path' )
226 $this->stash->repo, $thumbnailImage->getStoragePath(),
false );
228 $this->outputLocalFile( $thumbFile );
249 private function outputRemoteScaledThumb(
$file, $params, $flags ) {
253 $scalerThumbName =
$file->generateThumbName(
$file->getName(), $params );
257 $thumbProxyUrl =
$file->getRepo()->getThumbProxyUrl();
258 if ( strlen( $thumbProxyUrl ) ) {
259 $scalerThumbUrl = $thumbProxyUrl .
'temp/' .
$file->getUrlRel() .
260 '/' . rawurlencode( $scalerThumbName );
261 $secret =
$file->getRepo()->getThumbProxySecret();
266 $scalerBaseUrl = $this->
getConfig()->get( MainConfigNames::UploadStashScalerBaseUrl );
268 if ( preg_match(
'/^\/\//', $scalerBaseUrl ) ) {
275 $scalerThumbUrl = $scalerBaseUrl .
'/' .
$file->getUrlRel() .
276 '/' . rawurlencode( $scalerThumbName );
286 $req = $this->httpRequestFactory->create( $scalerThumbUrl, $httpOptions, __METHOD__ );
289 if ( strlen( $secret ) ) {
290 $req->setHeader(
'X-Swift-Secret', $secret );
293 $status = $req->execute();
294 if ( !$status->isOK() ) {
295 $errors = $status->getErrorsArray();
298 'uploadstash-file-not-found-no-remote-thumb',
299 print_r( $errors, 1 ),
304 $contentType = $req->getResponseHeader(
"content-type" );
305 if ( !$contentType ) {
307 $this->
msg(
'uploadstash-file-not-found-missing-content-type' )
311 $this->outputContents( $req->getContent(), $contentType );
322 private function outputLocalFile(
File $file ) {
323 if (
$file->getSize() > self::MAX_SERVE_BYTES ) {
325 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
329 $file->getRepo()->streamFileWithStatus(
$file->getPath(),
330 [
'Content-Transfer-Encoding: binary',
331 'Expires: Sun, 17-Jan-2038 19:14:07 GMT' ]
342 private function outputContents(
$content, $contentType ) {
344 if ( $size > self::MAX_SERVE_BYTES ) {
346 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
351 self::outputFileHeaders( $contentType, $size );
364 private static function outputFileHeaders( $contentType, $size ) {
365 header(
"Content-Type: $contentType",
true );
366 header(
'Content-Transfer-Encoding: binary',
true );
367 header(
'Expires: Sun, 17-Jan-2038 19:14:07 GMT',
true );
369 header(
'Cache-Control: private' );
370 header(
"Content-Length: $size",
true );
377 private function showUploads() {
391 ], $this->
getContext(),
'clearStashedUploads' );
393 $form->setSubmitDestructive();
394 $form->setSubmitCallback(
function ( $formData, $form ) {
395 if ( isset( $formData[
'Clear'] ) ) {
396 wfDebug(
'stash has: ' . print_r( $this->stash->listFiles(),
true ) );
398 if ( !$this->stash->clear() ) {
405 $form->setSubmitTextMsg(
'uploadstash-clear' );
407 $form->prepareForm();
408 $formResult = $form->tryAuthorizedSubmit();
412 $refreshHtml = $linkRenderer->makeKnownLink(
414 $this->
msg(
'uploadstash-refresh' )->text()
416 $files = $this->stash->listFiles();
417 if ( $files && count( $files ) ) {
419 $fileListItemsHtml =
'';
420 foreach ( $files as
$file ) {
421 $itemHtml = $linkRenderer->makeKnownLink(
426 $fileObj = $this->stash->getFile(
$file );
427 $thumb = $fileObj->generateThumbName(
$file, [
'width' => 220 ] );
429 $this->
msg(
'word-separator' )->escaped() .
430 $this->
msg(
'parentheses' )->rawParams(
431 $linkRenderer->makeKnownLink(
432 $this->getPageTitle(
"thumb/$file/$thumb" ),
433 $this->msg(
'uploadstash-thumbnail' )->text()
436 }
catch ( TimeoutException $e ) {
438 }
catch ( Exception $e ) {
443 $this->
getOutput()->addHTML( Html::rawElement(
'ul', [], $fileListItemsHtml ) );
444 $form->displayForm( $formResult );
445 $this->
getOutput()->addHTML( Html::rawElement(
'p', [], $refreshHtml ) );
447 $this->
getOutput()->addHTML( Html::rawElement(
'p', [],
448 Html::element(
'span', [], $this->
msg(
'uploadstash-nofiles' )->text() )
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getPageTitle( $subpage=false)
Get a self-referential title object.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Shortcut to construct a special page which is unlisted by default.