77 private const MAX_SERVE_BYTES = 1048576;
89 parent::__construct(
'UploadStash',
'upload' );
91 $this->httpRequestFactory = $httpRequestFactory;
92 $this->urlUtils = $urlUtils;
109 $this->stash = $this->localRepo->getUploadStash( $this->
getUser() );
112 if ( $subPage ===
null || $subPage ===
'' ) {
113 $this->showUploads();
131 $params = $this->parseKey( $key );
132 if ( $params[
'type'] ===
'thumb' ) {
133 $this->outputThumbFromStash( $params[
'file'], $params[
'params'] );
135 $this->outputLocalFile( $params[
'file'] );
140 $message = $e->getMessage();
141 }
catch ( Exception $e ) {
143 $message = $e->getMessage();
158 private function parseKey( $key ) {
159 $type = strtok( $key,
'/' );
161 if ( $type !==
'file' && $type !==
'thumb' ) {
163 $this->
msg(
'uploadstash-bad-path-unknown-type', $type )
166 $fileName = strtok(
'/' );
167 $thumbPart = strtok(
'/' );
168 $file = $this->stash->getFile( $fileName );
169 if ( $type ===
'thumb' ) {
170 $srcNamePos = strrpos( $thumbPart, $fileName );
171 if ( $srcNamePos ===
false || $srcNamePos < 1 ) {
173 $this->
msg(
'uploadstash-bad-path-unrecognized-thumb-name' )
176 $paramString = substr( $thumbPart, 0, $srcNamePos - 1 );
178 $handler =
$file->getHandler();
180 $params = $handler->parseParamString( $paramString );
182 return [
'file' =>
$file,
'type' => $type,
'params' => $params ];
185 $this->
msg(
'uploadstash-bad-path-no-handler', $file->getMimeType(),
$file->getPath() )
190 return [
'file' =>
$file,
'type' => $type ];
199 private function outputThumbFromStash(
$file, $params ) {
205 if (
$file->getRepo()->getThumbProxyUrl()
208 $this->outputRemoteScaledThumb(
$file, $params );
210 $this->outputLocallyScaledThumb(
$file, $params );
221 private function outputLocallyScaledThumb(
$file, $params ) {
225 $thumbnailImage =
$file->transform( $params, File::RENDER_NOW );
226 if ( !$thumbnailImage ) {
228 $this->
msg(
'uploadstash-file-not-found-no-thumb' )
233 if ( !$thumbnailImage->getStoragePath() ) {
235 $this->
msg(
'uploadstash-file-not-found-no-local-path' )
242 $this->stash->repo, $thumbnailImage->getStoragePath(),
false );
244 $this->outputLocalFile( $thumbFile );
264 private function outputRemoteScaledThumb(
$file, $params ) {
268 $scalerThumbName =
$file->generateThumbName(
$file->getName(), $params );
272 $thumbProxyUrl =
$file->getRepo()->getThumbProxyUrl();
273 if ( strlen( $thumbProxyUrl ) ) {
274 $scalerThumbUrl = $thumbProxyUrl .
'temp/' .
$file->getUrlRel() .
275 '/' . rawurlencode( $scalerThumbName );
276 $secret =
$file->getRepo()->getThumbProxySecret();
283 if ( preg_match(
'/^\/\//', $scalerBaseUrl ) ) {
287 $scalerBaseUrl = $this->urlUtils->expand( $scalerBaseUrl,
PROTO_CANONICAL );
290 $scalerThumbUrl = $scalerBaseUrl .
'/' .
$file->getUrlRel() .
291 '/' . rawurlencode( $scalerThumbName );
301 $req = $this->httpRequestFactory->create( $scalerThumbUrl, $httpOptions, __METHOD__ );
304 if ( strlen( $secret ) ) {
305 $req->setHeader(
'X-Swift-Secret', $secret );
308 $status = $req->execute();
309 if ( !$status->isOK() ) {
310 $errors = $status->getErrorsArray();
313 'uploadstash-file-not-found-no-remote-thumb',
314 print_r( $errors, 1 ),
319 $contentType = $req->getResponseHeader(
"content-type" );
320 if ( !$contentType ) {
322 $this->
msg(
'uploadstash-file-not-found-missing-content-type' )
326 $this->outputContents( $req->getContent(), $contentType );
337 private function outputLocalFile(
File $file ) {
338 if (
$file->getSize() > self::MAX_SERVE_BYTES ) {
340 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
344 $file->getRepo()->streamFileWithStatus(
$file->getPath(),
345 [
'Content-Transfer-Encoding: binary',
346 'Expires: Sun, 17-Jan-2038 19:14:07 GMT' ]
357 private function outputContents(
$content, $contentType ) {
359 if ( $size > self::MAX_SERVE_BYTES ) {
361 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
366 self::outputFileHeaders( $contentType, $size );
379 private static function outputFileHeaders( $contentType, $size ) {
380 header(
"Content-Type: $contentType",
true );
381 header(
'Content-Transfer-Encoding: binary',
true );
382 header(
'Expires: Sun, 17-Jan-2038 19:14:07 GMT',
true );
384 header(
'Cache-Control: private' );
385 header(
"Content-Length: $size",
true );
392 private function showUploads() {
406 ], $this->
getContext(),
'clearStashedUploads' );
408 $form->setSubmitDestructive();
409 $form->setSubmitCallback(
function ( $formData, $form ) {
410 if ( isset( $formData[
'Clear'] ) ) {
411 wfDebug(
'stash has: ' . print_r( $this->stash->listFiles(),
true ) );
413 if ( !$this->stash->clear() ) {
414 return Status::newFatal(
'uploadstash-errclear' );
418 return Status::newGood();
420 $form->setSubmitTextMsg(
'uploadstash-clear' );
422 $form->prepareForm();
423 $formResult = $form->tryAuthorizedSubmit();
427 $refreshHtml = $linkRenderer->makeKnownLink(
429 $this->
msg(
'uploadstash-refresh' )->text()
431 $files = $this->stash->listFiles();
432 if ( $files && count( $files ) ) {
434 $fileListItemsHtml =
'';
435 foreach ( $files as
$file ) {
436 $itemHtml = $linkRenderer->makeKnownLink(
441 $fileObj = $this->stash->getFile(
$file );
442 $thumb = $fileObj->generateThumbName(
$file, [
'width' => 220 ] );
444 $this->
msg(
'word-separator' )->escaped() .
445 $this->
msg(
'parentheses' )->rawParams(
446 $linkRenderer->makeKnownLink(
447 $this->getPageTitle(
"thumb/$file/$thumb" ),
448 $this->msg(
'uploadstash-thumbnail' )->text()
451 }
catch ( TimeoutException $e ) {
453 }
catch ( Exception $e ) {
456 $fileListItemsHtml .= Html::rawElement(
'li', [], $itemHtml );
458 $this->
getOutput()->addHTML( Html::rawElement(
'ul', [], $fileListItemsHtml ) );
459 $form->displayForm( $formResult );
460 $this->
getOutput()->addHTML( Html::rawElement(
'p', [], $refreshHtml ) );
462 $this->
getOutput()->addHTML( Html::rawElement(
'p', [],
463 Html::element(
'span', [], $this->
msg(
'uploadstash-nofiles' )->text() )