76 private const MAX_SERVE_BYTES = 1_048_576;
84 parent::__construct(
'UploadStash',
'upload' );
86 $this->httpRequestFactory = $httpRequestFactory;
87 $this->urlUtils = $urlUtils;
88 $this->dbProvider = $dbProvider;
105 $this->stash = $this->localRepo->getUploadStash( $this->
getUser() );
108 if ( $subPage ===
null || $subPage ===
'' ) {
109 $this->showUploads();
127 $params = $this->parseKey( $key );
128 if ( $params[
'type'] ===
'thumb' ) {
129 $this->outputThumbFromStash( $params[
'file'], $params[
'params'] );
131 $this->outputLocalFile( $params[
'file'] );
136 $message = $e->getMessage();
137 }
catch ( Exception $e ) {
139 $message = $e->getMessage();
154 private function parseKey( $key ) {
155 $type = strtok( $key,
'/' );
157 if ( $type !==
'file' && $type !==
'thumb' ) {
159 $this->
msg(
'uploadstash-bad-path-unknown-type', $type )
162 $fileName = strtok(
'/' );
163 $thumbPart = strtok(
'/' );
164 $file = $this->stash->getFile( $fileName );
165 if ( $type ===
'thumb' ) {
166 $srcNamePos = strrpos( $thumbPart, $fileName );
167 if ( $srcNamePos ===
false || $srcNamePos < 1 ) {
169 $this->
msg(
'uploadstash-bad-path-unrecognized-thumb-name' )
172 $paramString = substr( $thumbPart, 0, $srcNamePos - 1 );
174 $handler = $file->getHandler();
176 $params = $handler->parseParamString( $paramString );
177 if ( $params ===
false ) {
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 );
220 private function outputLocallyScaledThumb( $file, $params ) {
224 $thumbnailImage = $file->transform( $params, File::RENDER_NOW );
225 if ( !$thumbnailImage ) {
227 $this->
msg(
'uploadstash-file-not-found-no-thumb' )
232 if ( !$thumbnailImage->getStoragePath() ) {
234 $this->
msg(
'uploadstash-file-not-found-no-local-path' )
240 $thumbFile =
new UnregisteredLocalFile(
false,
241 $this->stash->repo, $thumbnailImage->getStoragePath(),
false );
243 $this->outputLocalFile( $thumbFile );
262 private function outputRemoteScaledThumb( $file, $params ) {
266 $scalerThumbName = $file->generateThumbName( $file->getName(), $params );
270 $thumbProxyUrl = $file->getRepo()->getThumbProxyUrl();
271 if ( $thumbProxyUrl !==
null ) {
272 $scalerThumbUrl = $thumbProxyUrl .
'temp/' . $file->getUrlRel() .
273 '/' . rawurlencode( $scalerThumbName );
274 $secret = $file->getRepo()->getThumbProxySecret();
281 if ( preg_match(
'/^\/\//', $scalerBaseUrl ) ) {
285 $scalerBaseUrl = $this->urlUtils->expand( $scalerBaseUrl,
PROTO_CANONICAL );
288 $scalerThumbUrl = $scalerBaseUrl .
'/' . $file->getUrlRel() .
289 '/' . rawurlencode( $scalerThumbName );
299 $req = $this->httpRequestFactory->create( $scalerThumbUrl, $httpOptions, __METHOD__ );
302 if ( $secret !==
null ) {
303 $req->setHeader(
'X-Swift-Secret', $secret );
306 $status = $req->execute();
307 if ( !$status->isOK() ) {
310 'uploadstash-file-not-found-no-remote-thumb',
311 $status->getMessage(),
316 $contentType = $req->getResponseHeader(
"content-type" );
317 if ( !$contentType ) {
319 $this->
msg(
'uploadstash-file-not-found-missing-content-type' )
323 $this->outputContents( $req->getContent(), $contentType );
334 private function outputLocalFile( File $file ) {
335 if ( $file->getSize() > self::MAX_SERVE_BYTES ) {
337 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
341 $file->getRepo()->streamFileWithStatus( $file->getPath(),
342 [
'Content-Transfer-Encoding: binary',
343 'Expires: Sun, 17-Jan-2038 19:14:07 GMT' ]
354 private function outputContents( $content, $contentType ) {
355 $size = strlen( $content );
356 if ( $size > self::MAX_SERVE_BYTES ) {
358 $this->
msg(
'uploadstash-file-too-large', self::MAX_SERVE_BYTES )
363 self::outputFileHeaders( $contentType, $size );
376 private static function outputFileHeaders( $contentType, $size ) {
377 header(
"Content-Type: $contentType",
true );
378 header(
'Content-Transfer-Encoding: binary',
true );
379 header(
'Expires: Sun, 17-Jan-2038 19:14:07 GMT',
true );
381 header(
'Cache-Control: private' );
382 header(
"Content-Length: $size",
true );
389 private function showUploads() {
397 $form = HTMLForm::factory(
'ooui', [
403 ], $this->
getContext(),
'clearStashedUploads' );
405 $form->setSubmitDestructive();
406 $form->setSubmitCallback(
function ( $formData, $form ) {
407 if ( isset( $formData[
'Clear'] ) ) {
408 wfDebug(
'stash has: ' . print_r( $this->stash->listFiles(),
true ) );
410 if ( !$this->stash->clear() ) {
411 return Status::newFatal(
'uploadstash-errclear' );
415 return Status::newGood();
417 $form->setSubmitTextMsg(
'uploadstash-clear' );
419 $form->prepareForm();
420 $formResult = $form->tryAuthorizedSubmit();
424 $refreshHtml = $linkRenderer->makeKnownLink(
426 $this->
msg(
'uploadstash-refresh' )->text()
428 $pager =
new UploadStashPager(
435 if ( $pager->getNumRows() ) {
437 $this->
getOutput()->addParserOutputContent(
438 $pager->getFullOutput(),
439 ParserOptions::newFromContext( $this->getContext() )
441 $form->displayForm( $formResult );
442 $this->
getOutput()->addHTML( Html::rawElement(
'p', [], $refreshHtml ) );
444 $this->
getOutput()->addHTML( Html::rawElement(
'p', [],