* Revert r76503
[lhc/web/wiklou.git] / includes / specials / SpecialUploadStash.php
1 <?php
2 /**
3 * Implements Special:UploadStash
4 *
5 * Web access for files temporarily stored by UploadStash.
6 *
7 * For example -- files that were uploaded with the UploadWizard extension are stored temporarily
8 * before committing them to the db. But we want to see their thumbnails and get other information
9 * about them.
10 *
11 * Since this is based on the user's session, in effect this creates a private temporary file area.
12 * However, the URLs for the files cannot be shared.
13 *
14 * @file
15 * @ingroup SpecialPage
16 * @ingroup Upload
17 */
18
19 class SpecialUploadStash extends UnlistedSpecialPage {
20 // UploadStash
21 private $stash;
22
23 // we should not be reading in really big files and serving them out
24 private $maxServeFileSize = 262144; // 256K
25
26 // $request is the request (usually wgRequest)
27 // $subpage is everything in the URL after Special:UploadStash
28 public function __construct( $name, $restriction = '', $function = false, $file = 'default' ) {
29 parent::__construct( $name, 'upload' );
30 try {
31 $this->stash = new UploadStash( );
32 } catch (UploadStashNotAvailableException $e) {
33 return null;
34 }
35 }
36
37 /**
38 * If file available in stash, cats it out to the client as a simple HTTP response.
39 * n.b. Most sanity checking done in UploadStashLocalFile, so this is straightforward.
40 *
41 * @param $subPage String: subpage, e.g. in http://example.com/wiki/Special:UploadStash/foo.jpg, the "foo.jpg" part
42 * @return Boolean: success
43 */
44 public function execute( $subPage ) {
45 global $wgOut, $wgUser;
46
47 if ( !$this->userCanExecute( $wgUser ) ) {
48 $this->displayRestrictionError();
49 return;
50 }
51
52 // prevent callers from doing standard HTML output -- we'll take it from here
53 $wgOut->disable();
54
55 try {
56 $file = $this->getStashFile( $subPage );
57 if ( $file->getSize() > $this->maxServeFileSize ) {
58 throw new MWException( 'file size too large' );
59 }
60 $this->outputFile( $file );
61 return true;
62
63 } catch( UploadStashFileNotFoundException $e ) {
64 $code = 404;
65 } catch( UploadStashBadPathException $e ) {
66 $code = 403;
67 } catch( Exception $e ) {
68 $code = 500;
69 }
70
71 wfHttpError( $code, OutputPage::getStatusMessage( $code ), $e->getMessage() );
72 return false;
73 }
74
75
76 /**
77 * Convert the incoming url portion (subpage of Special page) into a stashed file,
78 * if available.
79 *
80 * @param $subPage String
81 * @return File object
82 * @throws MWException, UploadStashFileNotFoundException, UploadStashBadPathException
83 */
84 private function getStashFile( $subPage ) {
85 // due to an implementation quirk (and trying to be compatible with older method)
86 // the stash key doesn't have an extension
87 $key = $subPage;
88 $n = strrpos( $subPage, '.' );
89 if ( $n !== false ) {
90 $key = $n ? substr( $subPage, 0, $n ) : $subPage;
91 }
92
93 try {
94 $file = $this->stash->getFile( $key );
95 } catch ( UploadStashFileNotFoundException $e ) {
96 // if we couldn't find it, and it looks like a thumbnail,
97 // and it looks like we have the original, go ahead and generate it
98 $matches = array();
99 if ( ! preg_match( '/^(\d+)px-(.*)$/', $key, $matches ) ) {
100 // that doesn't look like a thumbnail. re-raise exception
101 throw $e;
102 }
103
104 list( $dummy, $width, $origKey ) = $matches;
105
106 // do not trap exceptions, if key is in bad format, or file not found,
107 // let exceptions propagate to caller.
108 $origFile = $this->stash->getFile( $origKey );
109
110 // ok we're here so the original must exist. Generate the thumbnail.
111 // because the file is a UploadStashFile, this thumbnail will also be stashed,
112 // and a thumbnailFile will be created in the thumbnailImage composite object
113 $thumbnailImage = $origFile->transform( array( 'width' => $width ) );
114 if ( !$thumbnailImage ) {
115 throw new MWException( 'Could not obtain thumbnail' );
116 }
117 $file = $thumbnailImage->thumbnailFile;
118 }
119
120 return $file;
121 }
122
123 /**
124 * Output HTTP response for file
125 * Side effects, obviously, of echoing lots of stuff to stdout.
126 *
127 * @param $file File object
128 */
129 private function outputFile( $file ) {
130 header( 'Content-Type: ' . $file->getMimeType(), true );
131 header( 'Content-Transfer-Encoding: binary', true );
132 header( 'Expires: Sun, 17-Jan-2038 19:14:07 GMT', true );
133 header( 'Pragma: public', true );
134 header( 'Content-Length: ' . $file->getSize(), true ); // FIXME: PHP can handle Content-Length for you just fine --RK
135 readfile( $file->getPath() );
136 }
137 }