Index: trunk/phase3/includes/upload/UploadBase.php |
— | — | @@ -236,7 +236,10 @@ |
237 | 237 | */ |
238 | 238 | global $wgMaxUploadSize; |
239 | 239 | if( $this->mFileSize > $wgMaxUploadSize ) { |
240 | | - return array( 'status' => self::FILE_TOO_LARGE ); |
| 240 | + return array( |
| 241 | + 'status' => self::FILE_TOO_LARGE, |
| 242 | + 'max' => $wgMaxUploadSize, |
| 243 | + ); |
241 | 244 | } |
242 | 245 | |
243 | 246 | /** |
Index: trunk/phase3/includes/upload/UploadFromFile.php |
— | — | @@ -8,16 +8,18 @@ |
9 | 9 | * Implements regular file uploads |
10 | 10 | */ |
11 | 11 | class UploadFromFile extends UploadBase { |
| 12 | + protected $mWebUpload = null; |
12 | 13 | |
13 | | - |
14 | 14 | function initializeFromRequest( &$request ) { |
| 15 | + $this->mWebUpload = $request->getUpload( 'wpUploadFile' ); |
| 16 | + |
15 | 17 | $desiredDestName = $request->getText( 'wpDestFile' ); |
16 | 18 | if( !$desiredDestName ) |
17 | | - $desiredDestName = $request->getFileName( 'wpUploadFile' ); |
| 19 | + $desiredDestName = $this->mWebUpload->getName(); |
18 | 20 | return $this->initializePathInfo( |
19 | 21 | $desiredDestName, |
20 | | - $request->getFileTempName( 'wpUploadFile' ), |
21 | | - $request->getFileSize( 'wpUploadFile' ) |
| 22 | + $this->mWebUpload->getTempName(), |
| 23 | + $this->mWebUpload->getSize() |
22 | 24 | ); |
23 | 25 | } |
24 | 26 | /** |
— | — | @@ -27,6 +29,35 @@ |
28 | 30 | return $this->initializePathInfo( $name, $tempPath, $fileSize ); |
29 | 31 | } |
30 | 32 | static function isValidRequest( $request ) { |
31 | | - return (bool)$request->getFileTempName( 'wpUploadFile' ); |
| 33 | + # Allow all requests, even if no file is present, so that an error |
| 34 | + # because a post_max_size or upload_max_filesize overflow |
| 35 | + return true; |
32 | 36 | } |
| 37 | + |
| 38 | + public function verifyUpload() { |
| 39 | + # Check for a post_max_size or upload_max_size overflow, so that a |
| 40 | + # proper error can be shown to the user |
| 41 | + if ( is_null( $this->mTempPath ) || $this->isEmptyFile() ) { |
| 42 | + # Using the Content-length header is not an absolutely fail-safe |
| 43 | + # method, but the only available option. Otherwise broken uploads |
| 44 | + # will be handled by the parent method and return empty-file |
| 45 | + $contentLength = intval( $_SERVER['CONTENT_LENGTH'] ); |
| 46 | + $maxPostSize = wfShorthandToInteger( ini_get( 'post_max_size' ) ); |
| 47 | + if ( $this->mWebUpload->getError() == UPLOAD_ERR_INI_SIZE |
| 48 | + || $contentLength > $maxPostSize ) { |
| 49 | + |
| 50 | + global $wgMaxUploadSize; |
| 51 | + return array( |
| 52 | + 'status' => self::FILE_TOO_LARGE, |
| 53 | + 'max' => min( |
| 54 | + $wgMaxUploadSize, |
| 55 | + wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ), |
| 56 | + $maxPostSize |
| 57 | + ), |
| 58 | + ); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + return parent::verifyUpload(); |
| 63 | + } |
33 | 64 | } |
Index: trunk/phase3/includes/WebRequest.php |
— | — | @@ -590,23 +590,20 @@ |
591 | 591 | * @return string or NULL if no such file. |
592 | 592 | */ |
593 | 593 | public function getFileTempname( $key ) { |
594 | | - if( !isset( $_FILES[$key] ) ) { |
595 | | - return null; |
596 | | - } |
597 | | - return $_FILES[$key]['tmp_name']; |
| 594 | + $file = new WebRequestUpload( $key ); |
| 595 | + return $file->getTempName(); |
598 | 596 | } |
599 | 597 | |
600 | 598 | /** |
601 | 599 | * Return the size of the upload, or 0. |
602 | 600 | * |
| 601 | + * @deprecated |
603 | 602 | * @param $key String: |
604 | 603 | * @return integer |
605 | 604 | */ |
606 | 605 | public function getFileSize( $key ) { |
607 | | - if( !isset( $_FILES[$key] ) ) { |
608 | | - return 0; |
609 | | - } |
610 | | - return $_FILES[$key]['size']; |
| 606 | + $file = new WebRequestUpload( $key ); |
| 607 | + return $file->getSize(); |
611 | 608 | } |
612 | 609 | |
613 | 610 | /** |
— | — | @@ -616,10 +613,8 @@ |
617 | 614 | * @return integer |
618 | 615 | */ |
619 | 616 | public function getUploadError( $key ) { |
620 | | - if( !isset( $_FILES[$key] ) || !isset( $_FILES[$key]['error'] ) ) { |
621 | | - return 0/*UPLOAD_ERR_OK*/; |
622 | | - } |
623 | | - return $_FILES[$key]['error']; |
| 617 | + $file = new WebRequestUpload( $key ); |
| 618 | + return $file->getError(); |
624 | 619 | } |
625 | 620 | |
626 | 621 | /** |
— | — | @@ -634,19 +629,19 @@ |
635 | 630 | * @return string or NULL if no such file. |
636 | 631 | */ |
637 | 632 | public function getFileName( $key ) { |
638 | | - global $wgContLang; |
639 | | - if( !isset( $_FILES[$key] ) ) { |
640 | | - return null; |
641 | | - } |
642 | | - $name = $_FILES[$key]['name']; |
643 | | - |
644 | | - # Safari sends filenames in HTML-encoded Unicode form D... |
645 | | - # Horrid and evil! Let's try to make some kind of sense of it. |
646 | | - $name = Sanitizer::decodeCharReferences( $name ); |
647 | | - $name = $wgContLang->normalize( $name ); |
648 | | - wfDebug( "WebRequest::getFileName() '" . $_FILES[$key]['name'] . "' normalized to '$name'\n" ); |
649 | | - return $name; |
| 633 | + $file = new WebRequestUpload( $key ); |
| 634 | + return $file->getName(); |
650 | 635 | } |
| 636 | + |
| 637 | + /** |
| 638 | + * Return a WebRequestUpload object corresponding to the key |
| 639 | + * |
| 640 | + * @param @key string |
| 641 | + * @return WebRequestUpload |
| 642 | + */ |
| 643 | + public function getUpload( $key ) { |
| 644 | + return new WebRequestUpload( $key ); |
| 645 | + } |
651 | 646 | |
652 | 647 | /** |
653 | 648 | * Return a handle to WebResponse style object, for setting cookies, |
— | — | @@ -770,6 +765,96 @@ |
771 | 766 | } |
772 | 767 | |
773 | 768 | /** |
| 769 | + * Object to access the $_FILES array |
| 770 | + */ |
| 771 | +class WebRequestUpload { |
| 772 | + protected $doesExist; |
| 773 | + protected $fileInfo; |
| 774 | + |
| 775 | + /** |
| 776 | + * Constructor. Should only be called by WebRequest |
| 777 | + * |
| 778 | + * @param $key string Key in $_FILES array (name of form field) |
| 779 | + */ |
| 780 | + public function __construct( $key ) { |
| 781 | + $this->doesExist = isset( $_FILES[$key] ); |
| 782 | + if ( $this->doesExist ) { |
| 783 | + $this->fileInfo = $_FILES[$key]; |
| 784 | + } |
| 785 | + } |
| 786 | + |
| 787 | + /** |
| 788 | + * Return whether a file with this name was uploaded. |
| 789 | + * |
| 790 | + * @return bool |
| 791 | + */ |
| 792 | + public function exists() { |
| 793 | + return $this->doesExist; |
| 794 | + } |
| 795 | + |
| 796 | + /** |
| 797 | + * Return the original filename of the uploaded file |
| 798 | + * |
| 799 | + * @return mixed Filename or null if non-existent |
| 800 | + */ |
| 801 | + public function getName() { |
| 802 | + if ( !$this->exists() ) { |
| 803 | + return null; |
| 804 | + } |
| 805 | + |
| 806 | + global $wgContLang; |
| 807 | + $name = $this->fileInfo['name']; |
| 808 | + |
| 809 | + # Safari sends filenames in HTML-encoded Unicode form D... |
| 810 | + # Horrid and evil! Let's try to make some kind of sense of it. |
| 811 | + $name = Sanitizer::decodeCharReferences( $name ); |
| 812 | + $name = $wgContLang->normalize( $name ); |
| 813 | + wfDebug( __METHOD__ . ": {$this->fileInfo['name']} normalized to '$name'\n" ); |
| 814 | + return $name; |
| 815 | + } |
| 816 | + |
| 817 | + /** |
| 818 | + * Return the file size of the uploaded file |
| 819 | + * |
| 820 | + * @return int File size or zero if non-existent |
| 821 | + */ |
| 822 | + public function getSize() { |
| 823 | + if ( !$this->exists() ) { |
| 824 | + return 0; |
| 825 | + } |
| 826 | + |
| 827 | + return $this->fileInfo['size']; |
| 828 | + } |
| 829 | + |
| 830 | + /** |
| 831 | + * Return the path to the temporary file |
| 832 | + * |
| 833 | + * @return mixed Path or null if non-existent |
| 834 | + */ |
| 835 | + public function getTempName() { |
| 836 | + if ( !$this->exists() ) { |
| 837 | + return null; |
| 838 | + } |
| 839 | + |
| 840 | + return $this->fileInfo['tmp_name']; |
| 841 | + } |
| 842 | + |
| 843 | + /** |
| 844 | + * Return the upload error. See link for explanation |
| 845 | + * http://www.php.net/manual/en/features.file-upload.errors.php |
| 846 | + * |
| 847 | + * @return int One of the UPLOAD_ constants, 0 if non-existent |
| 848 | + */ |
| 849 | + public function getError() { |
| 850 | + if ( !$this->exists() ) { |
| 851 | + return 0; # UPLOAD_ERR_OK |
| 852 | + } |
| 853 | + |
| 854 | + return $this->fileInfo['error']; |
| 855 | + } |
| 856 | +} |
| 857 | + |
| 858 | +/** |
774 | 859 | * WebRequest clone which takes values from a provided array. |
775 | 860 | * |
776 | 861 | * @ingroup HTTP |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -228,6 +228,7 @@ |
229 | 229 | 'WatchedItem' => 'includes/WatchedItem.php', |
230 | 230 | 'WatchlistEditor' => 'includes/WatchlistEditor.php', |
231 | 231 | 'WebRequest' => 'includes/WebRequest.php', |
| 232 | + 'WebRequestUpload' => 'includes/WebRequest.php', |
232 | 233 | 'WebResponse' => 'includes/WebResponse.php', |
233 | 234 | 'WikiError' => 'includes/WikiError.php', |
234 | 235 | 'WikiErrorMsg' => 'includes/WikiError.php', |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -253,6 +253,8 @@ |
254 | 254 | page. |
255 | 255 | * (bug 24517) LocalFile::newFromKey() and OldLocalFile::newFromKey() no longer |
256 | 256 | throw fatal errors |
| 257 | +* (bug 23380) Uploaded files that are larger than allowed by PHP now show a |
| 258 | + useful error message. |
257 | 259 | |
258 | 260 | === API changes in 1.17 === |
259 | 261 | * (bug 22738) Allow filtering by action type on query=logevent. |