r23023 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r23022‎ | r23023 | r23024 >
Date:02:55, 16 June 2007
Author:tstarling
Status:old
Tags:
Comment:
* Split off ultimate base class FileRepo from FSRepo
* Use rawurlencode() for paths instead of urlencode()
* Moved functionality of LocalFile::loadFromFile() to a public static function. This allows Special:Upload to entirely avoid loading metadata from the (potentially remote) store. Changed purgeMetadataCache() to use loadFromDB() instead of loadFromFile().
* Redefined private virtual URLs, giving them a repo name component instead of a host.
* Moved is_writable($wgUploadDirectory) in SpecialUpload.php to the repo
* Added some filename validation to the FSRepo's store/publish
* Changed store and publish to use relative destinations instead of absolute, as was documented
* Deprecated File::recordUpload()! Now use upload() to do both publish and record. Moved the UI bits to SpecialUpload.
* Create a null revision on reupload
* Changed most of the member variable names in UploadForm. $this->mUpload followed by some ambiguous word or abbreviation was not a good naming convention. Also did some reformatting and assorted code cleanup.
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/ImagePage.php (modified) (history)
  • /trunk/phase3/includes/LogPage.php (modified) (history)
  • /trunk/phase3/includes/SpecialUpload.php (modified) (history)
  • /trunk/phase3/includes/filerepo/FSRepo.php (modified) (history)
  • /trunk/phase3/includes/filerepo/File.php (modified) (history)
  • /trunk/phase3/includes/filerepo/FileRepo.php (added) (history)
  • /trunk/phase3/includes/filerepo/ForeignDBRepo.php (modified) (history)
  • /trunk/phase3/includes/filerepo/LocalFile.php (modified) (history)
  • /trunk/phase3/includes/filerepo/RepoGroup.php (modified) (history)
  • /trunk/phase3/includes/filerepo/UnregisteredLocalFile.php (modified) (history)
  • /trunk/phase3/tests/LocalFileTest.php (modified) (history)

Diff [purge]

Index: trunk/phase3/tests/LocalFileTest.php
@@ -68,17 +68,17 @@
6969 }
7070
7171 function testGetArchiveVirtualUrl() {
72 - $this->assertEquals( 'mwrepo:///public/archive', $this->file_hl0->getArchiveVirtualUrl() );
73 - $this->assertEquals( 'mwrepo:///public/archive/a/a2', $this->file_hl2->getArchiveVirtualUrl() );
74 - $this->assertEquals( 'mwrepo:///public/archive/%21', $this->file_hl0->getArchiveVirtualUrl( '!' ) );
75 - $this->assertEquals( 'mwrepo:///public/archive/a/a2/%21', $this->file_hl2->getArchiveVirtualUrl( '!' ) );
 72+ $this->assertEquals( 'mwrepo://test/public/archive', $this->file_hl0->getArchiveVirtualUrl() );
 73+ $this->assertEquals( 'mwrepo://test/public/archive/a/a2', $this->file_hl2->getArchiveVirtualUrl() );
 74+ $this->assertEquals( 'mwrepo://test/public/archive/%21', $this->file_hl0->getArchiveVirtualUrl( '!' ) );
 75+ $this->assertEquals( 'mwrepo://test/public/archive/a/a2/%21', $this->file_hl2->getArchiveVirtualUrl( '!' ) );
7676 }
7777
7878 function testGetThumbVirtualUrl() {
79 - $this->assertEquals( 'mwrepo:///public/thumb/Test%21', $this->file_hl0->getThumbVirtualUrl() );
80 - $this->assertEquals( 'mwrepo:///public/thumb/a/a2/Test%21', $this->file_hl2->getThumbVirtualUrl() );
81 - $this->assertEquals( 'mwrepo:///public/thumb/Test%21/%21', $this->file_hl0->getThumbVirtualUrl( '!' ) );
82 - $this->assertEquals( 'mwrepo:///public/thumb/a/a2/Test%21/%21', $this->file_hl2->getThumbVirtualUrl( '!' ) );
 79+ $this->assertEquals( 'mwrepo://test/public/thumb/Test%21', $this->file_hl0->getThumbVirtualUrl() );
 80+ $this->assertEquals( 'mwrepo://test/public/thumb/a/a2/Test%21', $this->file_hl2->getThumbVirtualUrl() );
 81+ $this->assertEquals( 'mwrepo://test/public/thumb/Test%21/%21', $this->file_hl0->getThumbVirtualUrl( '!' ) );
 82+ $this->assertEquals( 'mwrepo://test/public/thumb/a/a2/Test%21/%21', $this->file_hl2->getThumbVirtualUrl( '!' ) );
8383 }
8484
8585 function testGetUrl() {
Index: trunk/phase3/includes/ImagePage.php
@@ -664,7 +664,8 @@
665665 }
666666
667667 $sourcePath = $this->img->getArchiveVirtualUrl( $oldimage );
668 - $result = $this->img->publish( $sourcePath );
 668+ $comment = wfMsg( "reverted" );
 669+ $result = $this->img->upload( $sourcePath, $comment, $comment );
669670
670671 if ( WikiError::isError( $result ) ) {
671672 $this->showError( $result );
Index: trunk/phase3/includes/filerepo/LocalFile.php
@@ -150,58 +150,7 @@
151151 * Load metadata from the file itself
152152 */
153153 function loadFromFile() {
154 - wfProfileIn( __METHOD__ );
155 - $path = $this->getPath();
156 - $this->fileExists = file_exists( $path );
157 - $gis = array();
158 -
159 - if ( $this->fileExists ) {
160 - $magic=& MimeMagic::singleton();
161 -
162 - $this->mime = $magic->guessMimeType($path,true);
163 - list( $this->major_mime, $this->minor_mime ) = self::splitMime( $this->mime );
164 - $this->media_type = $magic->getMediaType($path,$this->mime);
165 - $handler = MediaHandler::getHandler( $this->mime );
166 -
167 - # Get size in bytes
168 - $this->size = filesize( $path );
169 -
170 - # Height, width and metadata
171 - if ( $handler ) {
172 - $gis = $handler->getImageSize( $this, $path );
173 - $this->metadata = $handler->getMetadata( $this, $path );
174 - } else {
175 - $gis = false;
176 - $this->metadata = '';
177 - }
178 -
179 - wfDebug(__METHOD__.": $path loaded, {$this->size} bytes, {$this->mime}.\n");
180 - } else {
181 - $this->mime = NULL;
182 - $this->media_type = MEDIATYPE_UNKNOWN;
183 - $this->metadata = '';
184 - wfDebug(__METHOD__.": $path NOT FOUND!\n");
185 - }
186 -
187 - if( $gis ) {
188 - $this->width = $gis[0];
189 - $this->height = $gis[1];
190 - } else {
191 - $this->width = 0;
192 - $this->height = 0;
193 - }
194 -
195 - #NOTE: $gis[2] contains a code for the image type. This is no longer used.
196 -
197 - #NOTE: we have to set this flag early to avoid load() to be called
198 - # be some of the functions below. This may lead to recursion or other bad things!
199 - # as ther's only one thread of execution, this should be safe anyway.
200 - $this->dataLoaded = true;
201 -
202 - if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits'];
203 - else $this->bits = 0;
204 -
205 - wfProfileOut( __METHOD__ );
 154+ $this->setProps( self::getInfoFromPath( $this->getPath() ) );
206155 }
207156
208157 function getCacheFields( $prefix = 'img_' ) {
@@ -349,6 +298,17 @@
350299 wfProfileOut( __METHOD__ );
351300 }
352301
 302+ function setProps( $info ) {
 303+ $this->dataLoaded = true;
 304+ $fields = $this->getCacheFields( '' );
 305+ $fields[] = 'fileExists';
 306+ foreach ( $fields as $field ) {
 307+ if ( isset( $info[$field] ) ) {
 308+ $this->$field = $info[$field];
 309+ }
 310+ }
 311+ }
 312+
353313 /** splitMime inherited */
354314 /** getName inherited */
355315 /** getTitle inherited */
@@ -517,21 +477,30 @@
518478 * Refresh metadata in memcached, but don't touch thumbnails or squid
519479 */
520480 function purgeMetadataCache() {
521 - clearstatcache();
522 - $this->loadFromFile();
 481+ $this->loadFromDB();
523482 $this->saveToCache();
524483 }
525484
526485 /**
527486 * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid
528487 */
529 - function purgeCache( $archiveFiles = array() ) {
530 - global $wgUseSquid;
531 -
 488+ function purgeCache() {
532489 // Refresh metadata cache
533490 $this->purgeMetadataCache();
534491
535492 // Delete thumbnails
 493+ $this->purgeThumbnails();
 494+
 495+ // Purge squid cache for this file
 496+ wfPurgeSquidServers( array( $this->getURL() ) );
 497+ }
 498+
 499+ /**
 500+ * Delete cached transformed files
 501+ */
 502+ function purgeThumbnails() {
 503+ global $wgUseSquid;
 504+ // Delete thumbnails
536505 $files = $this->getThumbnails();
537506 $dir = $this->getThumbPath();
538507 $urls = array();
@@ -548,10 +517,6 @@
549518
550519 // Purge the squid
551520 if ( $wgUseSquid ) {
552 - $urls[] = $this->getURL();
553 - foreach ( $archiveFiles as $file ) {
554 - $urls[] = $this->getArchiveUrl( $file );
555 - }
556521 wfPurgeSquidServers( $urls );
557522 }
558523 }
@@ -632,17 +597,66 @@
633598 /** isHashed inherited */
634599
635600 /**
 601+ * Upload a file and record it in the DB
 602+ * @param string $srcPath Source path or virtual URL
 603+ * @param string $comment Upload description
 604+ * @param string $pageText Text to use for the new description page, if a new description page is created
 605+ * @param integer $flags Flags for publish()
 606+ * @param array $props File properties, if known. This can be used to reduce the
 607+ * upload time when uploading virtual URLs for which the file info
 608+ * is already known
 609+ * @param string $timestamp Timestamp for img_timestamp, or false to use the current time
 610+ *
 611+ * @return Wikitext-formatted WikiError or true on success
 612+ */
 613+ function upload( $srcPath, $comment, $pageText, $flags = 0, $props = false, $timestamp = false ) {
 614+ $archive = $this->publish( $srcPath, $flags );
 615+ if ( WikiError::isError( $archive ) ){
 616+ return $archive;
 617+ }
 618+ if ( !$this->recordUpload2( $archive, $comment, $pageText, $props, $timestamp ) ) {
 619+ return new WikiErrorMsg( 'filenotfound', wfEscapeWikiText( $srcPath ) );
 620+ }
 621+ return true;
 622+ }
 623+
 624+ /**
636625 * Record a file upload in the upload log and the image table
 626+ * @deprecated use upload()
637627 */
638628 function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '',
639629 $watch = false, $timestamp = false )
640630 {
641 - global $wgUser, $wgUseCopyrightUpload;
 631+ $pageText = UploadForm::getInitialPageText( $desc, $license, $copyStatus, $source );
 632+ if ( !$this->recordUpload2( $oldver, $desc, $pageText ) ) {
 633+ return false;
 634+ }
 635+ if ( $watch ) {
 636+ global $wgUser;
 637+ $wgUser->addWatch( $this->getTitle() );
 638+ }
 639+ return true;
642640
 641+ }
 642+
 643+ /**
 644+ * Record a file upload in the upload log and the image table
 645+ */
 646+ function recordUpload2( $oldver, $comment, $pageText, $props = false, $timestamp = false )
 647+ {
 648+ global $wgUser;
 649+
643650 $dbw = $this->repo->getMasterDB();
644651
 652+ if ( !$props ) {
 653+ $props = $this->repo->getFileProps( $this->getVirtualUrl() );
 654+ }
 655+ $this->setProps( $props );
 656+
645657 // Delete thumbnails and refresh the metadata cache
646 - $this->purgeCache();
 658+ $this->purgeThumbnails();
 659+ $this->saveToCache();
 660+ wfPurgeSquidServers( array( $this->getURL() ) );
647661
648662 // Fail now if the file isn't there
649663 if ( !$this->fileExists ) {
@@ -650,37 +664,10 @@
651665 return false;
652666 }
653667
654 - if ( $wgUseCopyrightUpload ) {
655 - if ( $license != '' ) {
656 - $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
657 - }
658 - $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" .
659 - '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
660 - "$licensetxt" .
661 - '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
662 - } else {
663 - if ( $license != '' ) {
664 - $filedesc = $desc == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n";
665 - $textdesc = $filedesc .
666 - '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
667 - } else {
668 - $textdesc = $desc;
669 - }
670 - }
671 -
672668 if ( $timestamp === false ) {
673669 $timestamp = $dbw->timestamp();
674670 }
675671
676 - #split mime type
677 - if (strpos($this->mime,'/')!==false) {
678 - list($major,$minor)= explode('/',$this->mime,2);
679 - }
680 - else {
681 - $major= $this->mime;
682 - $minor= "unknown";
683 - }
684 -
685672 # Test to see if the row exists using INSERT IGNORE
686673 # This avoids race conditions by locking the row until the commit, and also
687674 # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
@@ -692,10 +679,10 @@
693680 'img_height' => intval( $this->height ),
694681 'img_bits' => $this->bits,
695682 'img_media_type' => $this->media_type,
696 - 'img_major_mime' => $major,
697 - 'img_minor_mime' => $minor,
 683+ 'img_major_mime' => $this->major_mime,
 684+ 'img_minor_mime' => $this->minor_mime,
698685 'img_timestamp' => $timestamp,
699 - 'img_description' => $desc,
 686+ 'img_description' => $comment,
700687 'img_user' => $wgUser->getID(),
701688 'img_user_text' => $wgUser->getName(),
702689 'img_metadata' => $this->metadata,
@@ -730,10 +717,10 @@
731718 'img_height' => intval( $this->height ),
732719 'img_bits' => $this->bits,
733720 'img_media_type' => $this->media_type,
734 - 'img_major_mime' => $major,
735 - 'img_minor_mime' => $minor,
 721+ 'img_major_mime' => $this->major_mime,
 722+ 'img_minor_mime' => $this->minor_mime,
736723 'img_timestamp' => $timestamp,
737 - 'img_description' => $desc,
 724+ 'img_description' => $comment,
738725 'img_user' => $wgUser->getID(),
739726 'img_user_text' => $wgUser->getName(),
740727 'img_metadata' => $this->metadata,
@@ -750,31 +737,28 @@
751738
752739 $descTitle = $this->getTitle();
753740 $article = new Article( $descTitle );
754 - $minor = false;
755 - $watch = $watch || $wgUser->isWatched( $descTitle );
756 - $suppressRC = true; // There's already a log entry, so don't double the RC load
757741
 742+ # Add the log entry
 743+ $log = new LogPage( 'upload' );
 744+ $log->addEntry( 'upload', $descTitle, $comment );
 745+
758746 if( $descTitle->exists() ) {
759 - // TODO: insert a null revision into the page history for this update.
760 - if( $watch ) {
761 - $wgUser->addWatch( $descTitle );
762 - }
 747+ # Create a null revision
 748+ $nullRevision = Revision::newNullRevision( $dbw, $descTitle->getArticleId(), $log->getRcComment(), false );
 749+ $nullRevision->insertOn( $dbw );
763750
764751 # Invalidate the cache for the description page
765752 $descTitle->invalidateCache();
766753 $descTitle->purgeSquid();
767754 } else {
768755 // New file; create the description page.
769 - $article->insertNewArticle( $textdesc, $desc, $minor, $watch, $suppressRC );
 756+ // There's already a log entry, so don't make a second RC entry
 757+ $article->doEdit( $pageText, $comment, EDIT_NEW | EDIT_SUPPRESS_RC );
770758 }
771759
772760 # Hooks, hooks, the magic of hooks...
773761 wfRunHooks( 'FileUpload', array( $this ) );
774762
775 - # Add the log entry
776 - $log = new LogPage( 'upload' );
777 - $log->addEntry( 'upload', $descTitle, $desc );
778 -
779763 # Commit the transaction now, in case something goes wrong later
780764 # The most important thing is that files don't get lost, especially archives
781765 $dbw->immediateCommit();
@@ -803,11 +787,11 @@
804788 * file, and a wikitext-formatted WikiError object on failure.
805789 */
806790 function publish( $srcPath, $flags = 0 ) {
807 - $dstPath = $this->getFullPath();
 791+ $dstRel = $this->getRel();
808792 $archiveName = gmdate( 'YmdHis' ) . '!'. $this->getName();
809 - $archivePath = $this->getArchivePath( $archiveName );
 793+ $archiveRel = 'archive/' . $this->getHashPath() . $archiveName;
810794 $flags = $flags & File::DELETE_SOURCE ? LocalRepo::DELETE_SOURCE : 0;
811 - $status = $this->repo->publish( $srcPath, $dstPath, $archivePath, $flags );
 795+ $status = $this->repo->publish( $srcPath, $dstRel, $archiveRel, $flags );
812796 if ( WikiError::isError( $status ) ) {
813797 return $status;
814798 } elseif ( $status == 'new' ) {
Index: trunk/phase3/includes/filerepo/UnregisteredLocalFile.php
@@ -92,7 +92,7 @@
9393
9494 function getURL() {
9595 if ( $this->repo ) {
96 - return $this->repo->getZoneUrl( 'public' ) . $this->repo->getHashPath( $this->name ) . urlencode( $this->name );
 96+ return $this->repo->getZoneUrl( 'public' ) . '/' . $this->repo->getHashPath( $this->name ) . urlencode( $this->name );
9797 } else {
9898 return false;
9999 }
Index: trunk/phase3/includes/filerepo/FSRepo.php
@@ -3,88 +3,23 @@
44 /**
55 * A repository for files accessible via the local filesystem. Does not support
66 * database access or registration.
7 - *
8 - * TODO: split off abstract base FileRepo
97 */
108
11 -class FSRepo {
12 - const DELETE_SOURCE = 1;
13 -
14 - var $directory, $url, $hashLevels, $thumbScriptUrl, $transformVia404;
15 - var $descBaseUrl, $scriptDirUrl, $articleUrl, $fetchDescription, $initialCapital;
 9+class FSRepo extends FileRepo {
 10+ var $directory, $url, $hashLevels;
1611 var $fileFactory = array( 'UnregisteredLocalFile', 'newFromTitle' );
1712 var $oldFileFactory = false;
1813
1914 function __construct( $info ) {
 15+ parent::__construct( $info );
 16+
2017 // Required settings
21 - $this->name = $info['name'];
2218 $this->directory = $info['directory'];
2319 $this->url = $info['url'];
2420 $this->hashLevels = $info['hashLevels'];
25 - $this->transformVia404 = !empty( $info['transformVia404'] );
26 -
27 - // Optional settings
28 - $this->initialCapital = true; // by default
29 - foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription',
30 - 'thumbScriptUrl', 'initialCapital' ) as $var )
31 - {
32 - if ( isset( $info[$var] ) ) {
33 - $this->$var = $info[$var];
34 - }
35 - }
3621 }
3722
3823 /**
39 - * Create a new File object from the local repository
40 - * @param mixed $title Title object or string
41 - * @param mixed $time Time at which the image is supposed to have existed.
42 - * If this is specified, the returned object will be an
43 - * instance of the repository's old file class instead of
44 - * a current file. Repositories not supporting version
45 - * control should return false if this parameter is set.
46 - */
47 - function newFile( $title, $time = false ) {
48 - if ( !($title instanceof Title) ) {
49 - $title = Title::makeTitleSafe( NS_IMAGE, $title );
50 - if ( !is_object( $title ) ) {
51 - return null;
52 - }
53 - }
54 - if ( $time ) {
55 - if ( $this->oldFileFactory ) {
56 - return call_user_func( $this->oldFileFactory, $title, $this, $time );
57 - } else {
58 - return false;
59 - }
60 - } else {
61 - return call_user_func( $this->fileFactory, $title, $this );
62 - }
63 - }
64 -
65 - /**
66 - * Find an instance of the named file that existed at the specified time
67 - * Returns false if the file did not exist. Repositories not supporting
68 - * version control should return false if the time is specified.
69 - *
70 - * @param mixed $time 14-character timestamp, or false for the current version
71 - */
72 - function findFile( $title, $time = false ) {
73 - # First try the current version of the file to see if it precedes the timestamp
74 - $img = $this->newFile( $title );
75 - if ( !$img ) {
76 - return false;
77 - }
78 - if ( $img->exists() && ( !$time || $img->getTimestamp() <= $time ) ) {
79 - return $img;
80 - }
81 - # Now try an old version of the file
82 - $img = $this->newFile( $title, $time );
83 - if ( $img->exists() ) {
84 - return $img;
85 - }
86 - }
87 -
88 - /**
8924 * Get the public root directory of the repository.
9025 */
9126 function getRootDirectory() {
@@ -106,20 +41,6 @@
10742 }
10843
10944 /**
110 - * Get the URL of thumb.php
111 - */
112 - function getThumbScriptUrl() {
113 - return $this->thumbScriptUrl;
114 - }
115 -
116 - /**
117 - * Returns true if the repository can transform files via a 404 handler
118 - */
119 - function canTransformVia404() {
120 - return $this->transformVia404;
121 - }
122 -
123 - /**
12445 * Get the local directory corresponding to one of the three basic zones
12546 */
12647 function getZonePath( $zone ) {
@@ -153,11 +74,13 @@
15475
15576 /**
15677 * Get a URL referring to this repository, with the private mwrepo protocol.
 78+ * The suffix, if supplied, is considered to be unencoded, and will be
 79+ * URL-encoded before being returned.
15780 */
15881 function getVirtualUrl( $suffix = false ) {
159 - $path = 'mwrepo://';
 82+ $path = 'mwrepo://' . $this->name;
16083 if ( $suffix !== false ) {
161 - $path .= '/' . $suffix;
 84+ $path .= '/' . rawurlencode( $suffix );
16285 }
16386 return $path;
16487 }
@@ -174,21 +97,24 @@
17598 if ( count( $bits ) != 3 ) {
17699 throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
177100 }
178 - list( $host, $zone, $rel ) = $bits;
179 - if ( $host !== '' ) {
 101+ list( $repo, $zone, $rel ) = $bits;
 102+ if ( $repo !== $this->name ) {
180103 throw new MWException( __METHOD__.": fetching from a foreign repo is not supported" );
181104 }
182105 $base = $this->getZonePath( $zone );
183106 if ( !$base ) {
184107 throw new MWException( __METHOD__.": invalid zone: $zone" );
185108 }
186 - return $base . '/' . urldecode( $rel );
 109+ return $base . '/' . rawurldecode( $rel );
187110 }
188111
189112 /**
190113 * Store a file to a given destination.
191114 */
192115 function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
 116+ if ( !is_writable( $this->directory ) ) {
 117+ return new WikiErrorMsg( 'upload_directory_read_only', wfEscapeWikiText( $this->directory ) );
 118+ }
193119 $root = $this->getZonePath( $dstZone );
194120 if ( !$root ) {
195121 throw new MWException( "Invalid zone: $dstZone" );
@@ -198,8 +124,8 @@
199125 if ( !is_dir( dirname( $dstPath ) ) ) {
200126 wfMkdirParents( dirname( $dstPath ) );
201127 }
202 -
203 - if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) {
 128+
 129+ if ( self::isVirtualUrl( $srcPath ) ) {
204130 $srcPath = $this->resolveVirtualUrl( $srcPath );
205131 }
206132
@@ -245,7 +171,7 @@
246172 * @return boolean True on success, false on failure
247173 */
248174 function freeTemp( $virtualUrl ) {
249 - $temp = 'mwrepo:///temp';
 175+ $temp = "mwrepo://{$this->name}/temp";
250176 if ( substr( $virtualUrl, 0, strlen( $temp ) ) != $temp ) {
251177 wfDebug( __METHOD__.": Invalid virtual URL\n" );
252178 return false;
@@ -263,16 +189,28 @@
264190 * virtual URL, into this repository at the specified destination location.
265191 *
266192 * @param string $srcPath The source path or URL
267 - * @param string $dstPath The destination relative path
268 - * @param string $archivePath The relative path where the existing file is to
269 - * be archived, if there is one.
270 - * @param integer $flags Bitfield, may be FSRepo::DELETE_SOURCE to indicate
 193+ * @param string $dstRel The destination relative path
 194+ * @param string $archiveRel The relative path where the existing file is to
 195+ * be archived, if there is one. Relative to the public zone root.
 196+ * @param integer $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
271197 * that the source file should be deleted if possible
272198 */
273 - function publish( $srcPath, $dstPath, $archivePath, $flags = 0 ) {
 199+ function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 ) {
 200+ if ( !is_writable( $this->directory ) ) {
 201+ return new WikiErrorMsg( 'upload_directory_read_only', wfEscapeWikiText( $this->directory ) );
 202+ }
274203 if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) {
275204 $srcPath = $this->resolveVirtualUrl( $srcPath );
276205 }
 206+ if ( !$this->validateFilename( $dstRel ) ) {
 207+ throw new MWException( 'Validation error in $dstRel' );
 208+ }
 209+ if ( !$this->validateFilename( $archiveRel ) ) {
 210+ throw new MWException( 'Validation error in $archiveRel' );
 211+ }
 212+ $dstPath = "{$this->directory}/$dstRel";
 213+ $archivePath = "{$this->directory}/$archiveRel";
 214+
277215 $dstDir = dirname( $dstPath );
278216 if ( !is_dir( $dstDir ) ) wfMkdirParents( $dstDir );
279217
@@ -324,84 +262,10 @@
325263 * If the repo is not hashed, returns an empty string
326264 */
327265 function getHashPath( $name ) {
328 - if ( $this->isHashed() ) {
329 - $hash = md5( $name );
330 - $path = '';
331 - for ( $i = 1; $i <= $this->hashLevels; $i++ ) {
332 - $path .= substr( $hash, 0, $i ) . '/';
333 - }
334 - return $path;
335 - } else {
336 - return '';
337 - }
 266+ return FileRepo::getHashPathForLevel( $name, $this->hashLevels );
338267 }
339268
340269 /**
341 - * Get the name of this repository, as specified by $info['name]' to the constructor
342 - */
343 - function getName() {
344 - return $this->name;
345 - }
346 -
347 - /**
348 - * Get the file description page base URL, or false if there isn't one.
349 - * @private
350 - */
351 - function getDescBaseUrl() {
352 - if ( is_null( $this->descBaseUrl ) ) {
353 - if ( !is_null( $this->articleUrl ) ) {
354 - $this->descBaseUrl = str_replace( '$1',
355 - urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':', $this->articleUrl );
356 - } elseif ( !is_null( $this->scriptDirUrl ) ) {
357 - $this->descBaseUrl = $this->scriptDirUrl . '/index.php?title=' .
358 - urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':';
359 - } else {
360 - $this->descBaseUrl = false;
361 - }
362 - }
363 - return $this->descBaseUrl;
364 - }
365 -
366 - /**
367 - * Get the URL of an image description page. May return false if it is
368 - * unknown or not applicable. In general this should only be called by the
369 - * File class, since it may return invalid results for certain kinds of
370 - * repositories. Use File::getDescriptionUrl() in user code.
371 - *
372 - * In particular, it uses the article paths as specified to the repository
373 - * constructor, whereas local repositories use the local Title functions.
374 - */
375 - function getDescriptionUrl( $name ) {
376 - $base = $this->getDescBaseUrl();
377 - if ( $base ) {
378 - return $base . wfUrlencode( $name );
379 - } else {
380 - return false;
381 - }
382 - }
383 -
384 - /**
385 - * Get the URL of the content-only fragment of the description page. For
386 - * MediaWiki this means action=render. This should only be called by the
387 - * repository's file class, since it may return invalid results. User code
388 - * should use File::getDescriptionText().
389 - */
390 - function getDescriptionRenderUrl( $name ) {
391 - if ( isset( $this->scriptDirUrl ) ) {
392 - return $this->scriptDirUrl . '/index.php?title=' .
393 - wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) . ':' . $name ) .
394 - '&action=render';
395 - } else {
396 - $descBase = $this->getDescBaseUrl();
397 - if ( $descBase ) {
398 - return wfAppendQuery( $descBase . wfUrlencode( $name ), 'action=render' );
399 - } else {
400 - return false;
401 - }
402 - }
403 - }
404 -
405 - /**
406270 * Call a callback function for every file in the repository.
407271 * Uses the filesystem even in child classes.
408272 */
@@ -424,7 +288,7 @@
425289 }
426290
427291 /**
428 - * Call a callaback function for every file in the repository
 292+ * Call a callback function for every file in the repository
429293 * May use either the database or the filesystem
430294 */
431295 function enumFiles( $callback ) {
@@ -432,20 +296,12 @@
433297 }
434298
435299 /**
436 - * Get the name of an image from its title object
 300+ * Get properties of a file with a given virtual URL
 301+ * The virtual URL must refer to this repo
437302 */
438 - function getNameFromTitle( $title ) {
439 - global $wgCapitalLinks;
440 - if ( $this->initialCapital != $wgCapitalLinks ) {
441 - global $wgContLang;
442 - $name = $title->getUserCaseDBKey();
443 - if ( $this->initialCapital ) {
444 - $name = $wgContLang->ucfirst( $name );
445 - }
446 - } else {
447 - $name = $title->getDBkey();
448 - }
449 - return $name;
 303+ function getFileProps( $virtualUrl ) {
 304+ $path = $this->resolveVirtualUrl( $virtualUrl );
 305+ return File::getPropsFromPath( $path );
450306 }
451307 }
452308
Index: trunk/phase3/includes/filerepo/File.php
@@ -503,7 +503,7 @@
504504 break;
505505 }
506506
507 - wfDebug( "Doing stat for $thumbPath\n" );
 507+ wfDebug( __METHOD__.": Doing stat for $thumbPath\n" );
508508 $this->migrateThumbFile( $thumbName );
509509 if ( file_exists( $thumbPath ) ) {
510510 $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params );
@@ -663,7 +663,7 @@
664664 * Get urlencoded relative path of the file
665665 */
666666 function getUrlRel() {
667 - return $this->getHashPath() . urlencode( $this->getName() );
 667+ return $this->getHashPath() . rawurlencode( $this->getName() );
668668 }
669669
670670 /** Get the path of the archive directory, or a particular file if $suffix is specified */
@@ -692,7 +692,7 @@
693693 if ( $suffix === false ) {
694694 $path = substr( $path, 0, -1 );
695695 } else {
696 - $path .= urlencode( $suffix );
 696+ $path .= rawurlencode( $suffix );
697697 }
698698 return $path;
699699 }
@@ -701,7 +701,7 @@
702702 function getThumbUrl( $suffix = false ) {
703703 $path = $this->repo->getZoneUrl('public') . '/thumb/' . $this->getUrlRel();
704704 if ( $suffix !== false ) {
705 - $path .= '/' . urlencode( $suffix );
 705+ $path .= '/' . rawurlencode( $suffix );
706706 }
707707 return $path;
708708 }
@@ -712,7 +712,7 @@
713713 if ( $suffix === false ) {
714714 $path = substr( $path, 0, -1 );
715715 } else {
716 - $path .= urlencode( $suffix );
 716+ $path .= rawurlencode( $suffix );
717717 }
718718 return $path;
719719 }
@@ -721,11 +721,20 @@
722722 function getThumbVirtualUrl( $suffix = false ) {
723723 $path = $this->repo->getVirtualUrl() . '/public/thumb/' . $this->getUrlRel();
724724 if ( $suffix !== false ) {
725 - $path .= '/' . urlencode( $suffix );
 725+ $path .= '/' . rawurlencode( $suffix );
726726 }
727727 return $path;
728728 }
729729
 730+ /** Get the virtual URL for the file itself */
 731+ function getVirtualUrl( $suffix = false ) {
 732+ $path = $this->repo->getVirtualUrl() . '/public/' . $this->getUrlRel();
 733+ if ( $suffix !== false ) {
 734+ $path .= '/' . rawurlencode( $suffix );
 735+ }
 736+ return $path;
 737+ }
 738+
730739 /**
731740 * @return bool
732741 */
@@ -990,6 +999,59 @@
9911000 function userCan( $field ) {
9921001 return true;
9931002 }
 1003+
 1004+ /**
 1005+ * Get an associative array containing information about a file in the local filesystem
 1006+ */
 1007+ static function getPropsFromPath( $path ) {
 1008+ wfProfileIn( __METHOD__ );
 1009+ wfDebug( __METHOD__.": Getting file info for $path\n" );
 1010+ $info = array( 'fileExists' => file_exists( $path ) );
 1011+ $gis = false;
 1012+ if ( $info['fileExists'] ) {
 1013+ $magic = MimeMagic::singleton();
 1014+
 1015+ $info['mime'] = $magic->guessMimeType( $path, true );
 1016+ list( $info['major_mime'], $info['minor_mime'] ) = self::splitMime( $info['mime'] );
 1017+ $info['media_type'] = $magic->getMediaType( $path, $info['mime'] );
 1018+
 1019+ # Get size in bytes
 1020+ $info['size'] = filesize( $path );
 1021+
 1022+ # Height, width and metadata
 1023+ $handler = MediaHandler::getHandler( $info['mime'] );
 1024+ if ( $handler ) {
 1025+ $tempImage = (object)array();
 1026+ $gis = $handler->getImageSize( $tempImage, $path );
 1027+ $info['metadata'] = $handler->getMetadata( $tempImage, $path );
 1028+ } else {
 1029+ $gis = false;
 1030+ $info['metadata'] = '';
 1031+ }
 1032+
 1033+ wfDebug(__METHOD__.": $path loaded, {$info['size']} bytes, {$info['mime']}.\n");
 1034+ } else {
 1035+ $info['mime'] = NULL;
 1036+ $info['media_type'] = MEDIATYPE_UNKNOWN;
 1037+ $info['metadata'] = '';
 1038+ wfDebug(__METHOD__.": $path NOT FOUND!\n");
 1039+ }
 1040+ if( $gis ) {
 1041+ # NOTE: $gis[2] contains a code for the image type. This is no longer used.
 1042+ $info['width'] = $gis[0];
 1043+ $info['height'] = $gis[1];
 1044+ if ( isset( $gis['bits'] ) ) {
 1045+ $info['bits'] = $gis['bits'];
 1046+ } else {
 1047+ $info['bits'] = 0;
 1048+ }
 1049+ } else {
 1050+ $info['width'] = 0;
 1051+ $info['height'] = 0;
 1052+ }
 1053+ wfProfileOut( __METHOD__ );
 1054+ return $info;
 1055+ }
9941056 }
9951057
9961058 ?>
Index: trunk/phase3/includes/filerepo/RepoGroup.php
@@ -116,6 +116,35 @@
117117 $class = $info['class'];
118118 return new $class( $info );
119119 }
 120+
 121+ /**
 122+ * Split a virtual URL into repo, zone and rel parts
 123+ * @return an array containing repo, zone and rel
 124+ */
 125+ function splitVirtualUrl( $url ) {
 126+ if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
 127+ throw new MWException( __METHOD__.': unknown protoocl' );
 128+ }
 129+
 130+ $bits = explode( '/', substr( $url, 9 ), 3 );
 131+ if ( count( $bits ) != 3 ) {
 132+ throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
 133+ }
 134+ return $bits;
 135+ }
 136+
 137+ function getFileProps( $fileName ) {
 138+ if ( FileRepo::isVirtualUrl( $fileName ) ) {
 139+ list( $repoName, $zone, $rel ) = $this->splitVirtualUrl( $fileName );
 140+ if ( $repoName === '' ) {
 141+ $repoName = 'local';
 142+ }
 143+ $repo = $this->getRepo( $repoName );
 144+ return $repo->getFileProps( $fileName );
 145+ } else {
 146+ return File::getPropsFromPath( $fileName );
 147+ }
 148+ }
120149 }
121150
122151 ?>
Index: trunk/phase3/includes/filerepo/FileRepo.php
@@ -0,0 +1,280 @@
 2+<?php
 3+
 4+/**
 5+ * Base class for file repositories
 6+ * Do not instantiate, use a derived class.
 7+ */
 8+abstract class FileRepo {
 9+ const DELETE_SOURCE = 1;
 10+
 11+ var $thumbScriptUrl, $transformVia404;
 12+ var $descBaseUrl, $scriptDirUrl, $articleUrl, $fetchDescription, $initialCapital;
 13+
 14+ /**
 15+ * Factory functions for creating new files
 16+ * Override these in the base class
 17+ */
 18+ var $fileFactory = false, $oldFileFactory = false;
 19+
 20+ function __construct( $info ) {
 21+ // Required settings
 22+ $this->name = $info['name'];
 23+
 24+ // Optional settings
 25+ $this->initialCapital = true; // by default
 26+ foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription',
 27+ 'thumbScriptUrl', 'initialCapital' ) as $var )
 28+ {
 29+ if ( isset( $info[$var] ) ) {
 30+ $this->$var = $info[$var];
 31+ }
 32+ }
 33+ $this->transformVia404 = !empty( $info['transformVia404'] );
 34+ }
 35+
 36+ /**
 37+ * Determine if a string is an mwrepo:// URL
 38+ */
 39+ static function isVirtualUrl( $url ) {
 40+ return substr( $url, 0, 9 ) == 'mwrepo://';
 41+ }
 42+
 43+ /**
 44+ * Create a new File object from the local repository
 45+ * @param mixed $title Title object or string
 46+ * @param mixed $time Time at which the image is supposed to have existed.
 47+ * If this is specified, the returned object will be an
 48+ * instance of the repository's old file class instead of
 49+ * a current file. Repositories not supporting version
 50+ * control should return false if this parameter is set.
 51+ */
 52+ function newFile( $title, $time = false ) {
 53+ if ( !($title instanceof Title) ) {
 54+ $title = Title::makeTitleSafe( NS_IMAGE, $title );
 55+ if ( !is_object( $title ) ) {
 56+ return null;
 57+ }
 58+ }
 59+ if ( $time ) {
 60+ if ( $this->oldFileFactory ) {
 61+ return call_user_func( $this->oldFileFactory, $title, $this, $time );
 62+ } else {
 63+ return false;
 64+ }
 65+ } else {
 66+ return call_user_func( $this->fileFactory, $title, $this );
 67+ }
 68+ }
 69+
 70+ /**
 71+ * Find an instance of the named file that existed at the specified time
 72+ * Returns false if the file did not exist. Repositories not supporting
 73+ * version control should return false if the time is specified.
 74+ *
 75+ * @param mixed $time 14-character timestamp, or false for the current version
 76+ */
 77+ function findFile( $title, $time = false ) {
 78+ # First try the current version of the file to see if it precedes the timestamp
 79+ $img = $this->newFile( $title );
 80+ if ( !$img ) {
 81+ return false;
 82+ }
 83+ if ( $img->exists() && ( !$time || $img->getTimestamp() <= $time ) ) {
 84+ return $img;
 85+ }
 86+ # Now try an old version of the file
 87+ $img = $this->newFile( $title, $time );
 88+ if ( $img->exists() ) {
 89+ return $img;
 90+ }
 91+ }
 92+
 93+ /**
 94+ * Get the URL of thumb.php
 95+ */
 96+ function getThumbScriptUrl() {
 97+ return $this->thumbScriptUrl;
 98+ }
 99+
 100+ /**
 101+ * Returns true if the repository can transform files via a 404 handler
 102+ */
 103+ function canTransformVia404() {
 104+ return $this->transformVia404;
 105+ }
 106+
 107+ /**
 108+ * Get the name of an image from its title object
 109+ */
 110+ function getNameFromTitle( $title ) {
 111+ global $wgCapitalLinks;
 112+ if ( $this->initialCapital != $wgCapitalLinks ) {
 113+ global $wgContLang;
 114+ $name = $title->getUserCaseDBKey();
 115+ if ( $this->initialCapital ) {
 116+ $name = $wgContLang->ucfirst( $name );
 117+ }
 118+ } else {
 119+ $name = $title->getDBkey();
 120+ }
 121+ return $name;
 122+ }
 123+
 124+ static function getHashPathForLevel( $name, $levels ) {
 125+ if ( $levels == 0 ) {
 126+ return '';
 127+ } else {
 128+ $hash = md5( $name );
 129+ $path = '';
 130+ for ( $i = 1; $i <= $levels; $i++ ) {
 131+ $path .= substr( $hash, 0, $i ) . '/';
 132+ }
 133+ return $path;
 134+ }
 135+ }
 136+
 137+ /**
 138+ * Get the name of this repository, as specified by $info['name]' to the constructor
 139+ */
 140+ function getName() {
 141+ return $this->name;
 142+ }
 143+
 144+ /**
 145+ * Get the file description page base URL, or false if there isn't one.
 146+ * @private
 147+ */
 148+ function getDescBaseUrl() {
 149+ if ( is_null( $this->descBaseUrl ) ) {
 150+ if ( !is_null( $this->articleUrl ) ) {
 151+ $this->descBaseUrl = str_replace( '$1',
 152+ wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':', $this->articleUrl );
 153+ } elseif ( !is_null( $this->scriptDirUrl ) ) {
 154+ $this->descBaseUrl = $this->scriptDirUrl . '/index.php?title=' .
 155+ wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':';
 156+ } else {
 157+ $this->descBaseUrl = false;
 158+ }
 159+ }
 160+ return $this->descBaseUrl;
 161+ }
 162+
 163+ /**
 164+ * Get the URL of an image description page. May return false if it is
 165+ * unknown or not applicable. In general this should only be called by the
 166+ * File class, since it may return invalid results for certain kinds of
 167+ * repositories. Use File::getDescriptionUrl() in user code.
 168+ *
 169+ * In particular, it uses the article paths as specified to the repository
 170+ * constructor, whereas local repositories use the local Title functions.
 171+ */
 172+ function getDescriptionUrl( $name ) {
 173+ $base = $this->getDescBaseUrl();
 174+ if ( $base ) {
 175+ return $base . wfUrlencode( $name );
 176+ } else {
 177+ return false;
 178+ }
 179+ }
 180+
 181+ /**
 182+ * Get the URL of the content-only fragment of the description page. For
 183+ * MediaWiki this means action=render. This should only be called by the
 184+ * repository's file class, since it may return invalid results. User code
 185+ * should use File::getDescriptionText().
 186+ */
 187+ function getDescriptionRenderUrl( $name ) {
 188+ if ( isset( $this->scriptDirUrl ) ) {
 189+ return $this->scriptDirUrl . '/index.php?title=' .
 190+ wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) . ':' . $name ) .
 191+ '&action=render';
 192+ } else {
 193+ $descBase = $this->getDescBaseUrl();
 194+ if ( $descBase ) {
 195+ return wfAppendQuery( $descBase . wfUrlencode( $name ), 'action=render' );
 196+ } else {
 197+ return false;
 198+ }
 199+ }
 200+ }
 201+
 202+ /**
 203+ * Store a file to a given destination.
 204+ */
 205+ abstract function store( $srcPath, $dstZone, $dstRel, $flags = 0 );
 206+
 207+ /**
 208+ * Pick a random name in the temp zone and store a file to it.
 209+ * Returns the URL, or a WikiError on failure.
 210+ * @param string $originalName The base name of the file as specified
 211+ * by the user. The file extension will be maintained.
 212+ * @param string $srcPath The current location of the file.
 213+ */
 214+ abstract function storeTemp( $originalName, $srcPath );
 215+
 216+ /**
 217+ * Remove a temporary file or mark it for garbage collection
 218+ * @param string $virtualUrl The virtual URL returned by storeTemp
 219+ * @return boolean True on success, false on failure
 220+ * STUB
 221+ */
 222+ function freeTemp( $virtualUrl ) {
 223+ return true;
 224+ }
 225+
 226+ /**
 227+ * Copy or move a file either from the local filesystem or from an mwrepo://
 228+ * virtual URL, into this repository at the specified destination location.
 229+ *
 230+ * @param string $srcPath The source path or URL
 231+ * @param string $dstRel The destination relative path
 232+ * @param string $archiveRel The relative path where the existing file is to
 233+ * be archived, if there is one. Relative to the public zone root.
 234+ * @param integer $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
 235+ * that the source file should be deleted if possible
 236+ */
 237+ abstract function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 );
 238+
 239+ /**
 240+ * Get properties of a file with a given virtual URL
 241+ * The virtual URL must refer to this repo
 242+ * Properties should ultimately be obtained via File::getPropsFromPath()
 243+ */
 244+ abstract function getFileProps( $virtualUrl );
 245+
 246+ /**
 247+ * Call a callback function for every file in the repository
 248+ * May use either the database or the filesystem
 249+ * STUB
 250+ */
 251+ function enumFiles( $callback ) {
 252+ throw new MWException( 'enumFiles is not supported by ' . get_class( $this ) );
 253+ }
 254+
 255+ /**
 256+ * Determine if a relative path is valid, i.e. not blank or involving directory traveral
 257+ */
 258+ function validateFilename( $filename ) {
 259+ if ( strval( $filename ) == '' ) {
 260+ return false;
 261+ }
 262+ if ( wfIsWindows() ) {
 263+ $filename = strtr( $filename, '\\', '/' );
 264+ }
 265+ /**
 266+ * Use the same traversal protection as Title::secureAndSplit()
 267+ */
 268+ if ( strpos( $filename, '.' ) !== false &&
 269+ ( $filename === '.' || $filename === '..' ||
 270+ strpos( $filename, './' ) === 0 ||
 271+ strpos( $filename, '../' ) === 0 ||
 272+ strpos( $filename, '/./' ) !== false ||
 273+ strpos( $filename, '/../' ) !== false ) )
 274+ {
 275+ return false;
 276+ } else {
 277+ return true;
 278+ }
 279+ }
 280+}
 281+?>
Property changes on: trunk/phase3/includes/filerepo/FileRepo.php
___________________________________________________________________
Added: svn:eol-style
1282 + native
Index: trunk/phase3/includes/filerepo/ForeignDBRepo.php
@@ -43,7 +43,7 @@
4444 return $this->hasSharedCache;
4545 }
4646
47 - function store( /*...*/ ) {
 47+ function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
4848 throw new MWException( get_class($this) . ': write operations are not supported' );
4949 }
5050 }
Index: trunk/phase3/includes/SpecialUpload.php
@@ -22,18 +22,19 @@
2323 /**#@+
2424 * @access private
2525 */
26 - var $mUploadFile, $mUploadDescription, $mLicense ,$mIgnoreWarning, $mUploadError;
27 - var $mUploadSaveName, $mUploadTempName, $mUploadSize, $mUploadOldVersion;
28 - var $mUploadCopyStatus, $mUploadSource, $mReUpload, $mAction, $mUpload;
29 - var $mOname, $mSessionKey, $mStashed, $mDestFile, $mRemoveTempFile, $mSourceType;
30 - var $mUploadTempFileSize = 0;
31 - var $mImage;
 26+ var $mComment, $mLicense, $mIgnoreWarning, $mCurlError;
 27+ var $mDestName, $mTempPath, $mFileSize, $mFileProps;
 28+ var $mCopyrightStatus, $mCopyrightSource, $mReUpload, $mAction, $mUploadClicked;
 29+ var $mSrcName, $mSessionKey, $mStashed, $mDesiredDestName, $mRemoveTempFile, $mSourceType;
 30+ var $mCurlDestHandle;
 31+ var $mLocalFile;
3232
3333 # Placeholders for text injection by hooks (must be HTML)
3434 # extensions should take care to _append_ to the present value
3535 var $uploadFormTextTop;
3636 var $uploadFormTextAfterSummary;
3737
 38+ const SESSION_VERSION = 1;
3839 /**#@-*/
3940
4041 /**
@@ -43,7 +44,7 @@
4445 */
4546 function UploadForm( &$request ) {
4647 global $wgAllowCopyUploads;
47 - $this->mDestFile = $request->getText( 'wpDestFile' );
 48+ $this->mDesiredDestName = $request->getText( 'wpDestFile' );
4849
4950 if( !$request->wasPosted() ) {
5051 # GET requests just give the main form; no data except wpDestfile.
@@ -56,21 +57,22 @@
5758
5859 $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' );
5960 $this->mReUpload = $request->getCheck( 'wpReUpload' );
60 - $this->mUpload = $request->getCheck( 'wpUpload' );
 61+ $this->mUploadClicked = $request->getCheck( 'wpUpload' );
6162
62 - $this->mUploadDescription = $request->getText( 'wpUploadDescription' );
 63+ $this->mComment = $request->getText( 'wpUploadDescription' );
6364 $this->mLicense = $request->getText( 'wpLicense' );
64 - $this->mUploadCopyStatus = $request->getText( 'wpUploadCopyStatus' );
65 - $this->mUploadSource = $request->getText( 'wpUploadSource' );
 65+ $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
 66+ $this->mCopyrightSource = $request->getText( 'wpUploadSource' );
6667 $this->mWatchthis = $request->getBool( 'wpWatchthis' );
67 - $this->mSourceType = $request->getText( 'wpSourceType' );
 68+ $this->mSourceType = $request->getText( 'wpSourceType' );
6869 wfDebug( "UploadForm: watchthis is: '$this->mWatchthis'\n" );
6970
7071 $this->mAction = $request->getVal( 'action' );
7172
7273 $this->mSessionKey = $request->getInt( 'wpSessionKey' );
7374 if( !empty( $this->mSessionKey ) &&
74 - isset( $_SESSION['wsUploadData'][$this->mSessionKey] ) ) {
 75+ isset( $_SESSION['wsUploadData'][$this->mSessionKey]['version'] ) &&
 76+ $_SESSION['wsUploadData'][$this->mSessionKey]['version'] == self::SESSION_VERSION ) {
7577 /**
7678 * Confirming a temporarily stashed upload.
7779 * We don't want path names to be forged, so we keep
@@ -78,10 +80,11 @@
7981 * an opaque key to the user agent.
8082 */
8183 $data = $_SESSION['wsUploadData'][$this->mSessionKey];
82 - $this->mUploadTempName = $data['mUploadTempName'];
83 - $this->mUploadSize = $data['mUploadSize'];
84 - $this->mOname = $data['mOname'];
85 - $this->mUploadError = 0/*UPLOAD_ERR_OK*/;
 84+ $this->mTempPath = $data['mTempPath'];
 85+ $this->mFileSize = $data['mFileSize'];
 86+ $this->mSrcName = $data['mSrcName'];
 87+ $this->mFileProps = $data['mFileProps'];
 88+ $this->mCurlError = 0/*UPLOAD_ERR_OK*/;
8689 $this->mStashed = true;
8790 $this->mRemoveTempFile = false;
8891 } else {
@@ -101,10 +104,11 @@
102105 * @access private
103106 */
104107 function initializeFromUpload( $request ) {
105 - $this->mUploadTempName = $request->getFileTempName( 'wpUploadFile' );
106 - $this->mUploadSize = $request->getFileSize( 'wpUploadFile' );
107 - $this->mOname = $request->getFileName( 'wpUploadFile' );
108 - $this->mUploadError = $request->getUploadError( 'wpUploadFile' );
 108+ $this->mTempPath = $request->getFileTempName( 'wpUploadFile' );
 109+ $this->mFileSize = $request->getFileSize( 'wpUploadFile' );
 110+ $this->mSrcName = $request->getFileName( 'wpUploadFile' );
 111+ $this->mCurlError = $request->getUploadError( 'wpUploadFile' );
 112+ $this->mFileProps = File::getPropsFromPath( $this->mTempPath );
109113 $this->mSessionKey = false;
110114 $this->mStashed = false;
111115 $this->mRemoveTempFile = false; // PHP will handle this
@@ -119,10 +123,10 @@
120124 $url = $request->getText( 'wpUploadFileURL' );
121125 $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' );
122126
123 - $this->mUploadTempName = $local_file;
124 - $this->mUploadError = $this->curlCopy( $url, $local_file );
125 - $this->mUploadSize = $this->mUploadTempFileSize;
126 - $this->mOname = array_pop( explode( '/', $url ) );
 127+ $this->mTempPath = $local_file;
 128+ $this->mFileSize = 0; # Will be set by curlCopy
 129+ $this->mCurlError = $this->curlCopy( $url, $local_file );
 130+ $this->mSrcName = array_pop( explode( '/', $url ) );
127131 $this->mSessionKey = false;
128132 $this->mStashed = false;
129133
@@ -151,8 +155,8 @@
152156 }
153157
154158 # Open temporary file
155 - $this->mUploadTempFile = @fopen( $this->mUploadTempName, "wb" );
156 - if( $this->mUploadTempFile === false ) {
 159+ $this->mCurlDestHandle = @fopen( $this->mTempPath, "wb" );
 160+ if( $this->mCurlDestHandle === false ) {
157161 # Could not open temporary file to write in
158162 $wgOut->errorPage( 'upload-file-error', 'upload-file-error-text');
159163 return true;
@@ -170,8 +174,8 @@
171175 // if ( $error ) print curl_error ( $ch ) ; # Debugging output
172176 curl_close( $ch );
173177
174 - fclose( $this->mUploadTempFile );
175 - unset( $this->mUploadTempFile );
 178+ fclose( $this->mCurlDestHandle );
 179+ unset( $this->mCurlDestHandle );
176180 if( $error ) {
177181 unlink( $dest );
178182 if( wfEmptyMsg( "upload-curl-error$errornum", wfMsg("upload-curl-error$errornum") ) )
@@ -192,11 +196,11 @@
193197 function uploadCurlCallback( $ch, $data ) {
194198 global $wgMaxUploadSize;
195199 $length = strlen( $data );
196 - $this->mUploadTempFileSize += $length;
197 - if( $this->mUploadTempFileSize > $wgMaxUploadSize ) {
 200+ $this->mFileSize += $length;
 201+ if( $this->mFileSize > $wgMaxUploadSize ) {
198202 return 0;
199203 }
200 - fwrite( $this->mUploadTempFile, $data );
 204+ fwrite( $this->mCurlDestHandle, $data );
201205 return $length;
202206 }
203207
@@ -206,11 +210,11 @@
207211 */
208212 function execute() {
209213 global $wgUser, $wgOut;
210 - global $wgEnableUploads, $wgUploadDirectory;
 214+ global $wgEnableUploads;
211215
212216 # Check uploading enabled
213217 if( !$wgEnableUploads ) {
214 - $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext', array( $this->mDestFile ) );
 218+ $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext', array( $this->mDesiredDestName ) );
215219 return;
216220 }
217221
@@ -235,18 +239,12 @@
236240 return;
237241 }
238242
239 - /** Check if the image directory is writeable, this is a common mistake */
240 - if( !is_writeable( $wgUploadDirectory ) ) {
241 - $wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $wgUploadDirectory ) );
242 - return;
243 - }
244 -
245243 if( $this->mReUpload ) {
246244 if( !$this->unsaveUploadedFile() ) {
247245 return;
248246 }
249247 $this->mainUploadForm();
250 - } else if( 'submit' == $this->mAction || $this->mUpload ) {
 248+ } else if( 'submit' == $this->mAction || $this->mUploadClicked ) {
251249 $this->processUpload();
252250 } else {
253251 $this->mainUploadForm();
@@ -272,7 +270,7 @@
273271 }
274272
275273 /* Check for PHP error if any, requires php 4.2 or newer */
276 - if( $this->mUploadError == 1/*UPLOAD_ERR_INI_SIZE*/ ) {
 274+ if( $this->mCurlError == 1/*UPLOAD_ERR_INI_SIZE*/ ) {
277275 $this->mainUploadForm( wfMsgHtml( 'largefileserver' ) );
278276 return;
279277 }
@@ -280,16 +278,16 @@
281279 /**
282280 * If there was no filename or a zero size given, give up quick.
283281 */
284 - if( trim( $this->mOname ) == '' || empty( $this->mUploadSize ) ) {
 282+ if( trim( $this->mSrcName ) == '' || empty( $this->mFileSize ) ) {
285283 $this->mainUploadForm( wfMsgHtml( 'emptyfile' ) );
286284 return;
287285 }
288286
289287 # Chop off any directories in the given filename
290 - if( $this->mDestFile ) {
291 - $basename = wfBaseName( $this->mDestFile );
 288+ if( $this->mDesiredDestName ) {
 289+ $basename = wfBaseName( $this->mDesiredDestName );
292290 } else {
293 - $basename = wfBaseName( $this->mOname );
 291+ $basename = wfBaseName( $this->mSrcName );
294292 }
295293
296294 /**
@@ -321,13 +319,13 @@
322320 * out of it. We'll strip some silently that Title would die on.
323321 */
324322 $filtered = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $basename );
325 - $nt = Title::newFromText( $filtered );
 323+ $nt = Title::makeTitleSafe( NS_IMAGE, $filtered );
326324 if( is_null( $nt ) ) {
327325 $this->uploadError( wfMsgWikiHtml( 'illegalfilename', htmlspecialchars( $filtered ) ) );
328326 return;
329327 }
330 - $nt =& Title::makeTitle( NS_IMAGE, $nt->getDBkey() );
331 - $this->mUploadSaveName = $nt->getDBkey();
 328+ $this->mLocalFile = wfLocalFile( $nt );
 329+ $this->mDestName = $this->mLocalFile->getName();
332330
333331 /**
334332 * If the image is protected, non-sysop users won't be able
@@ -340,7 +338,7 @@
341339 /**
342340 * In some cases we may forbid overwriting of existing files.
343341 */
344 - $overwrite = $this->checkOverwrite( $this->mUploadSaveName );
 342+ $overwrite = $this->checkOverwrite( $this->mDestName );
345343 if( WikiError::isError( $overwrite ) ) {
346344 return $this->uploadError( $overwrite->toString() );
347345 }
@@ -351,9 +349,9 @@
352350 if ($finalExt == '') {
353351 return $this->uploadError( wfMsgExt( 'filetype-missing', array ( 'parseinline' ) ) );
354352 } elseif ( $this->checkFileExtensionList( $ext, $wgFileBlacklist ) ||
355 - ($wgStrictFileExtensions &&
356 - !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) ) {
357 - return $this->uploadError( wfMsgExt( 'filetype-badtype', array ( 'parseinline' ), htmlspecialchars( $finalExt ), implode ( ', ', $wgFileExtensions ) ) );
 353+ ($wgStrictFileExtensions && !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) ) {
 354+ return $this->uploadError( wfMsgExt( 'filetype-badtype', array ( 'parseinline' ),
 355+ htmlspecialchars( $finalExt ), implode ( ', ', $wgFileExtensions ) ) );
358356 }
359357
360358 /**
@@ -363,7 +361,7 @@
364362 */
365363 if( !$this->mStashed ) {
366364 $this->checkMacBinary();
367 - $veri = $this->verify( $this->mUploadTempName, $finalExt );
 365+ $veri = $this->verify( $this->mTempPath, $finalExt );
368366
369367 if( $veri !== true ) { //it's a wiki error...
370368 return $this->uploadError( $veri->toString() );
@@ -374,7 +372,7 @@
375373 */
376374 $error = '';
377375 if( !wfRunHooks( 'UploadVerification',
378 - array( $this->mUploadSaveName, $this->mUploadTempName, &$error ) ) ) {
 376+ array( $this->mDestName, $this->mTempPath, &$error ) ) ) {
379377 return $this->uploadError( $error );
380378 }
381379 }
@@ -390,31 +388,31 @@
391389 if( $wgCapitalLinks ) {
392390 $filtered = ucfirst( $filtered );
393391 }
394 - if( $this->mUploadSaveName != $filtered ) {
395 - $warning .= '<li>'.wfMsgHtml( 'badfilename', htmlspecialchars( $this->mUploadSaveName ) ).'</li>';
 392+ if( $this->mDestName != $filtered ) {
 393+ $warning .= '<li>'.wfMsgHtml( 'badfilename', htmlspecialchars( $this->mDestName ) ).'</li>';
396394 }
397395
398396 global $wgCheckFileExtensions;
399397 if ( $wgCheckFileExtensions ) {
400398 if ( ! $this->checkFileExtension( $finalExt, $wgFileExtensions ) ) {
401 - $warning .= '<li>'.wfMsgExt( 'filetype-badtype', array ( 'parseinline' ), htmlspecialchars( $finalExt ), implode ( ', ', $wgFileExtensions ) ).'</li>';
 399+ $warning .= '<li>'.wfMsgExt( 'filetype-badtype', array ( 'parseinline' ),
 400+ htmlspecialchars( $finalExt ), implode ( ', ', $wgFileExtensions ) ).'</li>';
402401 }
403402 }
404403
405404 global $wgUploadSizeWarning;
406 - if ( $wgUploadSizeWarning && ( $this->mUploadSize > $wgUploadSizeWarning ) ) {
 405+ if ( $wgUploadSizeWarning && ( $this->mFileSize > $wgUploadSizeWarning ) ) {
407406 $skin = $wgUser->getSkin();
408407 $wsize = $skin->formatSize( $wgUploadSizeWarning );
409 - $asize = $skin->formatSize( $this->mUploadSize );
 408+ $asize = $skin->formatSize( $this->mFileSize );
410409 $warning .= '<li>' . wfMsgHtml( 'large-file', $wsize, $asize ) . '</li>';
411410 }
412 - if ( $this->mUploadSize == 0 ) {
 411+ if ( $this->mFileSize == 0 ) {
413412 $warning .= '<li>'.wfMsgHtml( 'emptyfile' ).'</li>';
414413 }
415414
416415 global $wgUser;
417416 $sk = $wgUser->getSkin();
418 - $image = wfLocalFile( $nt );
419417
420418 // Check for uppercase extension. We allow these filenames but check if an image
421419 // with lowercase extension exists already
@@ -423,13 +421,15 @@
424422 $image_lc = wfLocalFile( $nt_lc );
425423 }
426424
427 - if( $image->exists() ) {
 425+ if( $this->mLocalFile->exists() ) {
428426 $dlink = $sk->makeKnownLinkObj( $nt );
429 - if ( $image->allowInlineDisplay() ) {
430 - $dlink2 = $sk->makeImageLinkObj( $nt, wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ), $nt->getText(), 'right', array(), false, true );
431 - } elseif ( !$image->allowInlineDisplay() && $image->isSafeFile() ) {
432 - $icon = $image->iconThumb();
433 - $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' . $image->getURL() . '">' . $icon->toHtml() . '</a><br />' . $dlink . '</div>';
 427+ if ( $this->mLocalFile->allowInlineDisplay() ) {
 428+ $dlink2 = $sk->makeImageLinkObj( $nt, wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ),
 429+ $nt->getText(), 'right', array(), false, true );
 430+ } elseif ( !$this->mLocalFile->allowInlineDisplay() && $this->mLocalFile->isSafeFile() ) {
 431+ $icon = $this->mLocalFile->iconThumb();
 432+ $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' . $this->mLocalFile->getURL() . '">' .
 433+ $icon->toHtml() . '</a><br />' . $dlink . '</div>';
434434 } else {
435435 $dlink2 = '';
436436 }
@@ -441,17 +441,22 @@
442442 # It's not forbidden but in 99% it makes no sense to upload the same filename with uppercase extension
443443 $dlink = $sk->makeKnownLinkObj( $nt_lc );
444444 if ( $image_lc->allowInlineDisplay() ) {
445 - $dlink2 = $sk->makeImageLinkObj( $nt_lc, wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ), $nt_lc->getText(), 'right', array(), false, true );
 445+ $dlink2 = $sk->makeImageLinkObj( $nt_lc, wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ),
 446+ $nt_lc->getText(), 'right', array(), false, true );
446447 } elseif ( !$image_lc->allowInlineDisplay() && $image_lc->isSafeFile() ) {
447448 $icon = $image_lc->iconThumb();
448 - $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' . $image_lc->getURL() . '">' . $icon->toHtml() . '</a><br />' . $dlink . '</div>';
 449+ $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' . $image_lc->getURL() . '">' .
 450+ $icon->toHtml() . '</a><br />' . $dlink . '</div>';
449451 } else {
450452 $dlink2 = '';
451453 }
452454
453 - $warning .= '<li>' . wfMsgExt( 'fileexists-extension', 'parsemag' , $partname . '.' . $finalExt , $dlink ) . '</li>' . $dlink2;
 455+ $warning .= '<li>' . wfMsgExt( 'fileexists-extension', 'parsemag' , $partname . '.'
 456+ . $finalExt , $dlink ) . '</li>' . $dlink2;
454457
455 - } elseif ( ( substr( $partname , 3, 3 ) == 'px-' || substr( $partname , 2, 3 ) == 'px-' ) && ereg( "[0-9]{2}" , substr( $partname , 0, 2) ) ) {
 458+ } elseif ( ( substr( $partname , 3, 3 ) == 'px-' || substr( $partname , 2, 3 ) == 'px-' )
 459+ && ereg( "[0-9]{2}" , substr( $partname , 0, 2) ) )
 460+ {
456461 # Check for filenames like 50px- or 180px-, these are mostly thumbnails
457462 $nt_thb = Title::newFromText( substr( $partname , strpos( $partname , '-' ) +1 ) . '.' . $finalExt );
458463 $image_thb = wfLocalFile( $nt_thb );
@@ -459,26 +464,34 @@
460465 # Check if an image without leading '180px-' (or similiar) exists
461466 $dlink = $sk->makeKnownLinkObj( $nt_thb);
462467 if ( $image_thb->allowInlineDisplay() ) {
463 - $dlink2 = $sk->makeImageLinkObj( $nt_thb, wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ), $nt_thb->getText(), 'right', array(), false, true );
 468+ $dlink2 = $sk->makeImageLinkObj( $nt_thb,
 469+ wfMsgExt( 'fileexists-thumb', 'parseinline', $dlink ),
 470+ $nt_thb->getText(), 'right', array(), false, true );
464471 } elseif ( !$image_thb->allowInlineDisplay() && $image_thb->isSafeFile() ) {
465472 $icon = $image_thb->iconThumb();
466 - $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' . $image_thb->getURL() . '">' . $icon->toHtml() . '</a><br />' . $dlink . '</div>';
 473+ $dlink2 = '<div style="float:right" id="mw-media-icon"><a href="' .
 474+ $image_thb->getURL() . '">' . $icon->toHtml() . '</a><br />' .
 475+ $dlink . '</div>';
467476 } else {
468477 $dlink2 = '';
469478 }
470479
471 - $warning .= '<li>' . wfMsgExt( 'fileexists-thumbnail-yes', 'parsemag', $dlink ) . '</li>' . $dlink2;
 480+ $warning .= '<li>' . wfMsgExt( 'fileexists-thumbnail-yes', 'parsemag', $dlink ) .
 481+ '</li>' . $dlink2;
472482 } else {
473483 # Image w/o '180px-' does not exists, but we do not like these filenames
474 - $warning .= '<li>' . wfMsgExt( 'file-thumbnail-no', 'parseinline' , substr( $partname , 0, strpos( $partname , '-' ) +1 ) ) . '</li>';
 484+ $warning .= '<li>' . wfMsgExt( 'file-thumbnail-no', 'parseinline' ,
 485+ substr( $partname , 0, strpos( $partname , '-' ) +1 ) ) . '</li>';
475486 }
476487 }
477 - if ( $image->wasDeleted() ) {
 488+ if ( $this->mLocalFile->wasDeleted() ) {
478489 # If the file existed before and was deleted, warn the user of this
479490 # Don't bother doing so if the image exists now, however
480491 $ltitle = SpecialPage::getTitleFor( 'Log' );
481 - $llink = $sk->makeKnownLinkObj( $ltitle, wfMsgHtml( 'deletionlog' ), 'type=delete&page=' . $nt->getPrefixedUrl() );
482 - $warning .= wfOpenElement( 'li' ) . wfMsgWikiHtml( 'filewasdeleted', $llink ) . wfCloseElement( 'li' );
 492+ $llink = $sk->makeKnownLinkObj( $ltitle, wfMsgHtml( 'deletionlog' ),
 493+ 'type=delete&page=' . $nt->getPrefixedUrl() );
 494+ $warning .= wfOpenElement( 'li' ) . wfMsgWikiHtml( 'filewasdeleted', $llink ) .
 495+ wfCloseElement( 'li' );
483496 }
484497
485498 if( $warning != '' ) {
@@ -494,59 +507,24 @@
495508 * Try actually saving the thing...
496509 * It will show an error form on failure.
497510 */
498 - $hasBeenMunged = !empty( $this->mSessionKey ) || $this->mRemoveTempFile;
499 - if( $this->saveUploadedFile( $this->mUploadSaveName,
500 - $this->mUploadTempName,
501 - $hasBeenMunged ) ) {
502 - /**
503 - * Update the upload log and create the description page
504 - * if it's a new file.
505 - */
506 - $this->mImage = wfLocalFile( $this->mUploadSaveName );
507 - $success = $this->mImage->recordUpload( $this->mUploadOldVersion,
508 - $this->mUploadDescription,
509 - $this->mLicense,
510 - $this->mUploadCopyStatus,
511 - $this->mUploadSource,
512 - $this->mWatchthis );
 511+ $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
 512+ $this->mCopyrightStatus, $this->mCopyrightSource );
513513
514 - if ( $success ) {
515 - $this->showSuccess();
516 - wfRunHooks( 'UploadComplete', array( &$img ) );
517 - } else {
518 - // File::recordUpload() fails if the image went missing, which is
519 - // unlikely, hence the lack of a specialised message
520 - $wgOut->showFileNotFoundError( $this->mUploadSaveName );
 514+ $error = $this->mLocalFile->upload( $this->mTempPath, $this->mComment, $pageText,
 515+ File::DELETE_SOURCE, $this->mFileProps );
 516+ if ( WikiError::isError( $error ) ) {
 517+ $this->showError( $error );
 518+ } else {
 519+ if ( $this->mWatchthis ) {
 520+ global $wgUser;
 521+ $wgUser->addWatch( $this->mLocalFile->getTitle() );
521522 }
 523+ $this->showSuccess();
 524+ wfRunHooks( 'UploadComplete', array( &$img ) );
522525 }
523526 }
524527
525528 /**
526 - * Move the uploaded file from its temporary location to the final
527 - * destination. If a previous version of the file exists, move
528 - * it into the archive subdirectory.
529 - *
530 - * @todo If the later save fails, we may have disappeared the original file.
531 - *
532 - * @param string $saveName
533 - * @param string $tempName full path to the temporary file
534 - * @param bool $useRename if true, doesn't check that the source file
535 - * is a PHP-managed upload temporary
536 - */
537 - function saveUploadedFile( $saveName, $tempName, $useRename = false ) {
538 - global $wgOut, $wgAllowCopyUploads;
539 -
540 - $image = wfLocalFile( $saveName );
541 - $archiveName = $image->publish( $tempName, File::DELETE_SOURCE );
542 - if ( WikiError::isError( $archiveName ) ) {
543 - $this->showError( $archiveName );
544 - return false;
545 - }
546 - $this->mUploadOldVersion = $archiveName;
547 - return true;
548 - }
549 -
550 - /**
551529 * Stash a file in a temporary directory for later processing
552530 * after the user has confirmed it.
553531 *
@@ -580,8 +558,7 @@
581559 * @access private
582560 */
583561 function stashSession() {
584 - $stash = $this->saveTempUploadedFile(
585 - $this->mUploadSaveName, $this->mUploadTempName );
 562+ $stash = $this->saveTempUploadedFile( $this->mDestName, $this->mTempPath );
586563
587564 if( !$stash ) {
588565 # Couldn't save the file.
@@ -590,9 +567,12 @@
591568
592569 $key = mt_rand( 0, 0x7fffffff );
593570 $_SESSION['wsUploadData'][$key] = array(
594 - 'mUploadTempName' => $stash,
595 - 'mUploadSize' => $this->mUploadSize,
596 - 'mOname' => $this->mOname );
 571+ 'mTempPath' => $stash,
 572+ 'mFileSize' => $this->mFileSize,
 573+ 'mSrcName' => $this->mSrcName,
 574+ 'mFileProps' => $this->mFileProps,
 575+ 'version' => self::SESSION_VERSION,
 576+ );
597577 return $key;
598578 }
599579
@@ -604,9 +584,9 @@
605585 function unsaveUploadedFile() {
606586 global $wgOut;
607587 $repo = RepoGroup::singleton()->getLocalRepo();
608 - $success = $repo->freeTemp( $this->mUploadTempName );
 588+ $success = $repo->freeTemp( $this->mTempPath );
609589 if ( ! $success ) {
610 - $wgOut->showFileDeleteError( $this->mUploadTempName );
 590+ $wgOut->showFileDeleteError( $this->mTempPath );
611591 return false;
612592 } else {
613593 return true;
@@ -623,8 +603,8 @@
624604 global $wgUser, $wgOut, $wgContLang;
625605
626606 $sk = $wgUser->getSkin();
627 - $ilink = $sk->makeMediaLinkObj( $this->mImage->getTitle() );
628 - $dname = $wgContLang->getNsText( NS_IMAGE ) . ':'.$this->mUploadSaveName;
 607+ $ilink = $sk->makeMediaLinkObj( $this->mLocalFile->getTitle() );
 608+ $dname = $wgContLang->getNsText( NS_IMAGE ) . ':'.$this->mDestName;
629609 $dlink = $sk->makeKnownLink( $dname, $dname );
630610
631611 $wgOut->addHTML( '<h2>' . wfMsgHtml( 'successfulupload' ) . "</h2>\n" );
@@ -674,8 +654,8 @@
675655 if ( $wgUseCopyrightUpload )
676656 {
677657 $copyright = "
678 - <input type='hidden' name='wpUploadCopyStatus' value=\"" . htmlspecialchars( $this->mUploadCopyStatus ) . "\" />
679 - <input type='hidden' name='wpUploadSource' value=\"" . htmlspecialchars( $this->mUploadSource ) . "\" />
 658+ <input type='hidden' name='wpUploadCopyStatus' value=\"" . htmlspecialchars( $this->mCopyrightStatus ) . "\" />
 659+ <input type='hidden' name='wpUploadSource' value=\"" . htmlspecialchars( $this->mCopyrightSource ) . "\" />
680660 ";
681661 } else {
682662 $copyright = "";
@@ -685,9 +665,9 @@
686666 <form id='uploadwarning' method='post' enctype='multipart/form-data' action='$action'>
687667 <input type='hidden' name='wpIgnoreWarning' value='1' />
688668 <input type='hidden' name='wpSessionKey' value=\"" . htmlspecialchars( $this->mSessionKey ) . "\" />
689 - <input type='hidden' name='wpUploadDescription' value=\"" . htmlspecialchars( $this->mUploadDescription ) . "\" />
 669+ <input type='hidden' name='wpUploadDescription' value=\"" . htmlspecialchars( $this->mComment ) . "\" />
690670 <input type='hidden' name='wpLicense' value=\"" . htmlspecialchars( $this->mLicense ) . "\" />
691 - <input type='hidden' name='wpDestFile' value=\"" . htmlspecialchars( $this->mDestFile ) . "\" />
 671+ <input type='hidden' name='wpDestFile' value=\"" . htmlspecialchars( $this->mDesiredDestName ) . "\" />
692672 <input type='hidden' name='wpWatchthis' value=\"" . htmlspecialchars( intval( $this->mWatchthis ) ) . "\" />
693673 {$copyright}
694674 <table border='0'>
@@ -737,7 +717,7 @@
738718 "<span class='error'>{$msg}</span>\n" );
739719 }
740720 $wgOut->addHTML( '<div id="uploadtext">' );
741 - $wgOut->addWikiText( wfMsgNoTrans( 'uploadtext', $this->mDestFile ) );
 721+ $wgOut->addWikiText( wfMsgNoTrans( 'uploadtext', $this->mDesiredDestName ) );
742722 $wgOut->addHTML( '</div>' );
743723
744724 $sourcefilename = wfMsgHtml( 'sourcefilename' );
@@ -755,35 +735,44 @@
756736 $titleObj = SpecialPage::getTitleFor( 'Upload' );
757737 $action = $titleObj->escapeLocalURL();
758738
759 - $encDestFile = htmlspecialchars( $this->mDestFile );
 739+ $encDestName = htmlspecialchars( $this->mDesiredDestName );
760740
761741 $watchChecked =
762742 ( $wgUser->getOption( 'watchdefault' ) ||
763 - ( $wgUser->getOption( 'watchcreations' ) && $this->mDestFile == '' ) )
 743+ ( $wgUser->getOption( 'watchcreations' ) && $this->mDesiredDestName == '' ) )
764744 ? 'checked="checked"'
765745 : '';
766746
767747 // Prepare form for upload or upload/copy
768748 if( $wgAllowCopyUploads && $wgUser->isAllowed( 'upload_by_url' ) ) {
769749 $filename_form =
770 - "<input type='radio' id='wpSourceTypeFile' name='wpSourceType' value='file' onchange='toggle_element_activation(\"wpUploadFileURL\",\"wpUploadFile\")' checked />" .
771 - "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' onfocus='toggle_element_activation(\"wpUploadFileURL\",\"wpUploadFile\");toggle_element_check(\"wpSourceTypeFile\",\"wpSourceTypeURL\")'" .
772 - ($this->mDestFile?"":"onchange='fillDestFilename(\"wpUploadFile\")' ") . "size='40' />" .
 750+ "<input type='radio' id='wpSourceTypeFile' name='wpSourceType' value='file' " .
 751+ "onchange='toggle_element_activation(\"wpUploadFileURL\",\"wpUploadFile\")' checked />" .
 752+ "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' " .
 753+ "onfocus='" .
 754+ "toggle_element_activation(\"wpUploadFileURL\",\"wpUploadFile\");" .
 755+ "toggle_element_check(\"wpSourceTypeFile\",\"wpSourceTypeURL\")'" .
 756+ ($this->mDesiredDestName?"":"onchange='fillDestFilename(\"wpUploadFile\")' ") . "size='40' />" .
773757 wfMsgHTML( 'upload_source_file' ) . "<br/>" .
774 - "<input type='radio' id='wpSourceTypeURL' name='wpSourceType' value='web' onchange='toggle_element_activation(\"wpUploadFile\",\"wpUploadFileURL\")' />" .
775 - "<input tabindex='1' type='text' name='wpUploadFileURL' id='wpUploadFileURL' onfocus='toggle_element_activation(\"wpUploadFile\",\"wpUploadFileURL\");toggle_element_check(\"wpSourceTypeURL\",\"wpSourceTypeFile\")'" .
776 - ($this->mDestFile?"":"onchange='fillDestFilename(\"wpUploadFileURL\")' ") . "size='40' DISABLED />" .
 758+ "<input type='radio' id='wpSourceTypeURL' name='wpSourceType' value='web' " .
 759+ "onchange='toggle_element_activation(\"wpUploadFile\",\"wpUploadFileURL\")' />" .
 760+ "<input tabindex='1' type='text' name='wpUploadFileURL' id='wpUploadFileURL' " .
 761+ "onfocus='" .
 762+ "toggle_element_activation(\"wpUploadFile\",\"wpUploadFileURL\");" .
 763+ "toggle_element_check(\"wpSourceTypeURL\",\"wpSourceTypeFile\")'" .
 764+ ($this->mDesiredDestName?"":"onchange='fillDestFilename(\"wpUploadFileURL\")' ") . "size='40' DISABLED />" .
777765 wfMsgHtml( 'upload_source_url' ) ;
778766 } else {
779767 $filename_form =
780768 "<input tabindex='1' type='file' name='wpUploadFile' id='wpUploadFile' " .
781 - ($this->mDestFile?"":"onchange='fillDestFilename(\"wpUploadFile\")' ") .
 769+ ($this->mDesiredDestName?"":"onchange='fillDestFilename(\"wpUploadFile\")' ") .
782770 "size='40' />" .
783771 "<input type='hidden' name='wpSourceType' value='file' />" ;
784772 }
 773+ $encComment = htmlspecialchars( $this->mComment );
785774
786 - $wgOut->addHTML( "
787 - <form id='upload' method='post' enctype='multipart/form-data' action=\"$action\">
 775+ $wgOut->addHTML( <<<EOT
 776+ <form id='upload' method='post' enctype='multipart/form-data' action="$action">
788777 <table border='0'>
789778 <tr>
790779 {$this->uploadFormTextTop}
@@ -795,17 +784,20 @@
796785 <tr>
797786 <td align='right'><label for='wpDestFile'>{$destfilename}:</label></td>
798787 <td align='left'>
799 - <input tabindex='2' type='text' name='wpDestFile' id='wpDestFile' size='40' value=\"$encDestFile\" />
 788+ <input tabindex='2' type='text' name='wpDestFile' id='wpDestFile' size='40' value="$encDestName" />
800789 </td>
801790 </tr>
802791 <tr>
803792 <td align='right'><label for='wpUploadDescription'>{$summary}</label></td>
804793 <td align='left'>
805 - <textarea tabindex='3' name='wpUploadDescription' id='wpUploadDescription' rows='6' cols='{$cols}'{$ew}>" . htmlspecialchars( $this->mUploadDescription ) . "</textarea>
 794+ <textarea tabindex='3' name='wpUploadDescription' id='wpUploadDescription' rows='6'
 795+ cols='{$cols}'{$ew}>$encComment</textarea>
806796 {$this->uploadFormTextAfterSummary}
807797 </td>
808798 </tr>
809 - <tr>" );
 799+ <tr>
 800+EOT
 801+ );
810802
811803 if ( $licenseshtml != '' ) {
812804 global $wgStylePath;
@@ -826,17 +818,19 @@
827819
828820 if ( $wgUseCopyrightUpload ) {
829821 $filestatus = wfMsgHtml ( 'filestatus' );
830 - $copystatus = htmlspecialchars( $this->mUploadCopyStatus );
 822+ $copystatus = htmlspecialchars( $this->mCopyrightStatus );
831823 $filesource = wfMsgHtml ( 'filesource' );
832 - $uploadsource = htmlspecialchars( $this->mUploadSource );
 824+ $uploadsource = htmlspecialchars( $this->mCopyrightSource );
833825
834826 $wgOut->addHTML( "
835827 <td align='right' nowrap='nowrap'><label for='wpUploadCopyStatus'>$filestatus:</label></td>
836 - <td><input tabindex='5' type='text' name='wpUploadCopyStatus' id='wpUploadCopyStatus' value=\"$copystatus\" size='40' /></td>
 828+ <td><input tabindex='5' type='text' name='wpUploadCopyStatus' id='wpUploadCopyStatus'
 829+ value=\"$copystatus\" size='40' /></td>
837830 </tr>
838831 <tr>
839832 <td align='right'><label for='wpUploadCopyStatus'>$filesource:</label></td>
840 - <td><input tabindex='6' type='text' name='wpUploadSource' id='wpUploadCopyStatus' value=\"$uploadsource\" size='40' /></td>
 833+ <td><input tabindex='6' type='text' name='wpUploadSource' id='wpUploadCopyStatus'
 834+ value=\"$uploadsource\" size='40' /></td>
841835 </tr>
842836 <tr>
843837 ");
@@ -927,8 +921,6 @@
928922 $magic=& MimeMagic::singleton();
929923 $mime= $magic->guessMimeType($tmpfile,false);
930924
931 - $fname= "SpecialUpload::verify";
932 -
933925 #check mime type, if desired
934926 global $wgVerifyMimeType;
935927 if ($wgVerifyMimeType) {
@@ -959,7 +951,7 @@
960952 return new WikiErrorMsg( 'uploadvirus', htmlspecialchars($virus) );
961953 }
962954
963 - wfDebug( "$fname: all clear; passing.\n" );
 955+ wfDebug( __METHOD__.": all clear; passing.\n" );
964956 return true;
965957 }
966958
@@ -971,45 +963,46 @@
972964 * @return bool
973965 */
974966 function verifyExtension( $mime, $extension ) {
975 - $fname = 'SpecialUpload::verifyExtension';
976 -
977967 $magic =& MimeMagic::singleton();
978968
979969 if ( ! $mime || $mime == 'unknown' || $mime == 'unknown/unknown' )
980970 if ( ! $magic->isRecognizableExtension( $extension ) ) {
981 - wfDebug( "$fname: passing file with unknown detected mime type; unrecognized extension '$extension', can't verify\n" );
 971+ wfDebug( __METHOD__.": passing file with unknown detected mime type; " .
 972+ "unrecognized extension '$extension', can't verify\n" );
982973 return true;
983974 } else {
984 - wfDebug( "$fname: rejecting file with unknown detected mime type; recognized extension '$extension', so probably invalid file\n" );
 975+ wfDebug( __METHOD__.": rejecting file with unknown detected mime type; ".
 976+ "recognized extension '$extension', so probably invalid file\n" );
985977 return false;
986978 }
987979
988980 $match= $magic->isMatchingExtension($extension,$mime);
989981
990982 if ($match===NULL) {
991 - wfDebug( "$fname: no file extension known for mime type $mime, passing file\n" );
 983+ wfDebug( __METHOD__.": no file extension known for mime type $mime, passing file\n" );
992984 return true;
993985 } elseif ($match===true) {
994 - wfDebug( "$fname: mime type $mime matches extension $extension, passing file\n" );
 986+ wfDebug( __METHOD__.": mime type $mime matches extension $extension, passing file\n" );
995987
996988 #TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
997989 return true;
998990
999991 } else {
1000 - wfDebug( "$fname: mime type $mime mismatches file extension $extension, rejecting file\n" );
 992+ wfDebug( __METHOD__.": mime type $mime mismatches file extension $extension, rejecting file\n" );
1001993 return false;
1002994 }
1003995 }
1004996
1005 - /** Heuristig for detecting files that *could* contain JavaScript instructions or
1006 - * things that may look like HTML to a browser and are thus
1007 - * potentially harmful. The present implementation will produce false positives in some situations.
1008 - *
1009 - * @param string $file Pathname to the temporary upload file
1010 - * @param string $mime The mime type of the file
1011 - * @param string $extension The extension of the file
1012 - * @return bool true if the file contains something looking like embedded scripts
1013 - */
 997+ /**
 998+ * Heuristic for detecting files that *could* contain JavaScript instructions or
 999+ * things that may look like HTML to a browser and are thus
 1000+ * potentially harmful. The present implementation will produce false positives in some situations.
 1001+ *
 1002+ * @param string $file Pathname to the temporary upload file
 1003+ * @param string $mime The mime type of the file
 1004+ * @param string $extension The extension of the file
 1005+ * @return bool true if the file contains something looking like embedded scripts
 1006+ */
10141007 function detectScript($file, $mime, $extension) {
10151008 global $wgAllowTitlesInSVG;
10161009
@@ -1098,93 +1091,103 @@
10991092 return false;
11001093 }
11011094
1102 - /** Generic wrapper function for a virus scanner program.
1103 - * This relies on the $wgAntivirus and $wgAntivirusSetup variables.
1104 - * $wgAntivirusRequired may be used to deny upload if the scan fails.
1105 - *
1106 - * @param string $file Pathname to the temporary upload file
1107 - * @return mixed false if not virus is found, NULL if the scan fails or is disabled,
1108 - * or a string containing feedback from the virus scanner if a virus was found.
1109 - * If textual feedback is missing but a virus was found, this function returns true.
1110 - */
 1095+ /**
 1096+ * Generic wrapper function for a virus scanner program.
 1097+ * This relies on the $wgAntivirus and $wgAntivirusSetup variables.
 1098+ * $wgAntivirusRequired may be used to deny upload if the scan fails.
 1099+ *
 1100+ * @param string $file Pathname to the temporary upload file
 1101+ * @return mixed false if not virus is found, NULL if the scan fails or is disabled,
 1102+ * or a string containing feedback from the virus scanner if a virus was found.
 1103+ * If textual feedback is missing but a virus was found, this function returns true.
 1104+ */
11111105 function detectVirus($file) {
11121106 global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut;
11131107
1114 - $fname= "SpecialUpload::detectVirus";
1115 -
1116 - if (!$wgAntivirus) { #disabled?
1117 - wfDebug("$fname: virus scanner disabled\n");
1118 -
 1108+ if ( !$wgAntivirus ) {
 1109+ wfDebug( __METHOD__.": virus scanner disabled\n");
11191110 return NULL;
11201111 }
11211112
1122 - if (!$wgAntivirusSetup[$wgAntivirus]) {
1123 - wfDebug("$fname: unknown virus scanner: $wgAntivirus\n");
1124 -
1125 - $wgOut->addHTML( "<div class='error'>Bad configuration: unknown virus scanner: <i>$wgAntivirus</i></div>\n" ); #LOCALIZE
1126 -
 1113+ if ( !$wgAntivirusSetup[$wgAntivirus] ) {
 1114+ wfDebug( __METHOD__.": unknown virus scanner: $wgAntivirus\n" );
 1115+ # @TODO: localise
 1116+ $wgOut->addHTML( "<div class='error'>Bad configuration: unknown virus scanner: <i>$wgAntivirus</i></div>\n" );
11271117 return "unknown antivirus: $wgAntivirus";
11281118 }
11291119
1130 - #look up scanner configuration
1131 - $virus_scanner= $wgAntivirusSetup[$wgAntivirus]["command"]; #command pattern
1132 - $virus_scanner_codes= $wgAntivirusSetup[$wgAntivirus]["codemap"]; #exit-code map
1133 - $msg_pattern= $wgAntivirusSetup[$wgAntivirus]["messagepattern"]; #message pattern
 1120+ # look up scanner configuration
 1121+ $command = $wgAntivirusSetup[$wgAntivirus]["command"];
 1122+ $exitCodeMap = $wgAntivirusSetup[$wgAntivirus]["codemap"];
 1123+ $msgPattern = isset( $wgAntivirusSetup[$wgAntivirus]["messagepattern"] ) ?
 1124+ $wgAntivirusSetup[$wgAntivirus]["messagepattern"] : null;
11341125
1135 - $scanner= $virus_scanner; #copy, so we can resolve the pattern
 1126+ if ( strpos( $command,"%f" ) === false ) {
 1127+ # simple pattern: append file to scan
 1128+ $command .= " " . wfEscapeShellArg( $file );
 1129+ } else {
 1130+ # complex pattern: replace "%f" with file to scan
 1131+ $command = str_replace( "%f", wfEscapeShellArg( $file ), $command );
 1132+ }
11361133
1137 - if (strpos($scanner,"%f")===false) $scanner.= " ".wfEscapeShellArg($file); #simple pattern: append file to scan
1138 - else $scanner= str_replace("%f",wfEscapeShellArg($file),$scanner); #complex pattern: replace "%f" with file to scan
 1134+ wfDebug( __METHOD__.": running virus scan: $command \n" );
11391135
1140 - wfDebug("$fname: running virus scan: $scanner \n");
 1136+ # execute virus scanner
 1137+ $exitCode = false;
11411138
1142 - #execute virus scanner
1143 - $code= false;
1144 -
11451139 #NOTE: there's a 50 line workaround to make stderr redirection work on windows, too.
11461140 # that does not seem to be worth the pain.
11471141 # Ask me (Duesentrieb) about it if it's ever needed.
11481142 $output = array();
1149 - if (wfIsWindows()) exec("$scanner",$output,$code);
1150 - else exec("$scanner 2>&1",$output,$code);
 1143+ if ( wfIsWindows() ) {
 1144+ exec( "$command", $output, $exitCode );
 1145+ } else {
 1146+ exec( "$command 2>&1", $output, $exitCode );
 1147+ }
11511148
1152 - $exit_code= $code; #remember for user feedback
1153 -
1154 - if ($virus_scanner_codes) { #map exit code to AV_xxx constants.
1155 - if (isset($virus_scanner_codes[$code])) {
1156 - $code= $virus_scanner_codes[$code]; # explicit mapping
1157 - } else if (isset($virus_scanner_codes["*"])) {
1158 - $code= $virus_scanner_codes["*"]; # fallback mapping
 1149+ # map exit code to AV_xxx constants.
 1150+ $mappedCode = $exitCode;
 1151+ if ( $exitCodeMap ) {
 1152+ if ( isset( $exitCodeMap[$exitCode] ) ) {
 1153+ $mappedCode = $exitCodeMap[$exitCode];
 1154+ } elseif ( isset( $exitCodeMap["*"] ) ) {
 1155+ $mappedCode = $exitCodeMap["*"];
11591156 }
11601157 }
11611158
1162 - if ($code===AV_SCAN_FAILED) { #scan failed (code was mapped to false by $virus_scanner_codes)
1163 - wfDebug("$fname: failed to scan $file (code $exit_code).\n");
 1159+ if ( $mappedCode === AV_SCAN_FAILED ) {
 1160+ # scan failed (code was mapped to false by $exitCodeMap)
 1161+ wfDebug( __METHOD__.": failed to scan $file (code $exitCode).\n" );
11641162
1165 - if ($wgAntivirusRequired) { return "scan failed (code $exit_code)"; }
1166 - else { return NULL; }
1167 - }
1168 - else if ($code===AV_SCAN_ABORTED) { #scan failed because filetype is unknown (probably imune)
1169 - wfDebug("$fname: unsupported file type $file (code $exit_code).\n");
 1163+ if ( $wgAntivirusRequired ) {
 1164+ return "scan failed (code $exitCode)";
 1165+ } else {
 1166+ return NULL;
 1167+ }
 1168+ } else if ( $mappedCode === AV_SCAN_ABORTED ) {
 1169+ # scan failed because filetype is unknown (probably imune)
 1170+ wfDebug( __METHOD__.": unsupported file type $file (code $exitCode).\n" );
11701171 return NULL;
1171 - }
1172 - else if ($code===AV_NO_VIRUS) {
1173 - wfDebug("$fname: file passed virus scan.\n");
1174 - return false; #no virus found
1175 - }
1176 - else {
1177 - $output= join("\n",$output);
1178 - $output= trim($output);
 1172+ } else if ( $mappedCode === AV_NO_VIRUS ) {
 1173+ # no virus found
 1174+ wfDebug( __METHOD__.": file passed virus scan.\n" );
 1175+ return false;
 1176+ } else {
 1177+ $output = join( "\n", $output );
 1178+ $output = trim( $output );
11791179
1180 - if (!$output) $output= true; #if there's no output, return true
1181 - else if ($msg_pattern) {
1182 - $groups= array();
1183 - if (preg_match($msg_pattern,$output,$groups)) {
1184 - if ($groups[1]) $output= $groups[1];
 1180+ if ( !$output ) {
 1181+ $output = true; #if there's no output, return true
 1182+ } elseif ( $msgPattern ) {
 1183+ $groups = array();
 1184+ if ( preg_match( $msgPattern, $output, $groups ) ) {
 1185+ if ( $groups[1] ) {
 1186+ $output = $groups[1];
 1187+ }
11851188 }
11861189 }
11871190
1188 - wfDebug("$fname: FOUND VIRUS! scanner feedback: $output");
 1191+ wfDebug( __METHOD__.": FOUND VIRUS! scanner feedback: $output" );
11891192 return $output;
11901193 }
11911194 }
@@ -1198,7 +1201,7 @@
11991202 * @access private
12001203 */
12011204 function checkMacBinary() {
1202 - $macbin = new MacBinary( $this->mUploadTempName );
 1205+ $macbin = new MacBinary( $this->mTempPath );
12031206 if( $macbin->isValid() ) {
12041207 $dataFile = tempnam( wfTempDir(), "WikiMacBinary" );
12051208 $dataHandle = fopen( $dataFile, 'wb' );
@@ -1206,8 +1209,8 @@
12071210 wfDebug( "SpecialUpload::checkMacBinary: Extracting MacBinary data fork to $dataFile\n" );
12081211 $macbin->extractData( $dataHandle );
12091212
1210 - $this->mUploadTempName = $dataFile;
1211 - $this->mUploadSize = $macbin->dataForkLength();
 1213+ $this->mTempPath = $dataFile;
 1214+ $this->mFileSize = $macbin->dataForkLength();
12121215
12131216 // We'll have to manually remove the new file if it's not kept.
12141217 $this->mRemoveTempFile = true;
@@ -1221,9 +1224,9 @@
12221225 * @access private
12231226 */
12241227 function cleanupTempFile() {
1225 - if( $this->mRemoveTempFile && file_exists( $this->mUploadTempName ) ) {
1226 - wfDebug( "SpecialUpload::cleanupTempFile: Removing temporary file $this->mUploadTempName\n" );
1227 - unlink( $this->mUploadTempName );
 1228+ if ( $this->mRemoveTempFile && file_exists( $this->mTempPath ) ) {
 1229+ wfDebug( "SpecialUpload::cleanupTempFile: Removing temporary file {$this->mTempPath}\n" );
 1230+ unlink( $this->mTempPath );
12281231 }
12291232 }
12301233
@@ -1296,5 +1299,30 @@
12971300 $wgOut->enableClientCache( false );
12981301 $wgOut->addWikiText( $error->getMessage() );
12991302 }
 1303+
 1304+ /**
 1305+ * Get the initial image page text based on a comment and optional file status information
 1306+ */
 1307+ static function getInitialPageText( $comment, $license, $copyStatus, $source ) {
 1308+ global $wgUseCopyrightUpload;
 1309+ if ( $wgUseCopyrightUpload ) {
 1310+ if ( $license != '' ) {
 1311+ $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
 1312+ }
 1313+ $pageText = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $comment . "\n" .
 1314+ '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
 1315+ "$licensetxt" .
 1316+ '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
 1317+ } else {
 1318+ if ( $license != '' ) {
 1319+ $filedesc = $comment == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $comment . "\n";
 1320+ $pageText = $filedesc .
 1321+ '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
 1322+ } else {
 1323+ $pageText = $comment;
 1324+ }
 1325+ }
 1326+ return $pageText;
 1327+ }
13001328 }
13011329 ?>
Index: trunk/phase3/includes/AutoLoader.php
@@ -254,6 +254,7 @@
255255 # filerepo
256256 'ArchivedFile' => 'includes/filerepo/ArchivedFile.php',
257257 'File' => 'includes/filerepo/File.php',
 258+ 'FileRepo' => 'includes/filerepo/FileRepo.php',
258259 'ForeignDBFile' => 'includes/filerepo/ForeignDBFile.php',
259260 'ForeignDBRepo' => 'includes/filerepo/ForeignDBRepo.php',
260261 'FSRepo' => 'includes/filerepo/FSRepo.php',
Index: trunk/phase3/includes/DefaultSettings.php
@@ -308,34 +308,34 @@
309309 *
310310 * @global array $wgAntivirusSetup
311311 */
312 -$wgAntivirusSetup= array(
 312+$wgAntivirusSetup = array(
313313
314314 #setup for clamav
315315 'clamav' => array (
316316 'command' => "clamscan --no-summary ",
317317
318 - 'codemap'=> array (
319 - "0"=> AV_NO_VIRUS, #no virus
320 - "1"=> AV_VIRUS_FOUND, #virus found
321 - "52"=> AV_SCAN_ABORTED, #unsupported file format (probably imune)
322 - "*"=> AV_SCAN_FAILED, #else scan failed
 318+ 'codemap' => array (
 319+ "0" => AV_NO_VIRUS, # no virus
 320+ "1" => AV_VIRUS_FOUND, # virus found
 321+ "52" => AV_SCAN_ABORTED, # unsupported file format (probably imune)
 322+ "*" => AV_SCAN_FAILED, # else scan failed
323323 ),
324324
325 - 'messagepattern'=> '/.*?:(.*)/sim',
 325+ 'messagepattern' => '/.*?:(.*)/sim',
326326 ),
327327
328328 #setup for f-prot
329329 'f-prot' => array (
330330 'command' => "f-prot ",
331331
332 - 'codemap'=> array (
333 - "0"=> AV_NO_VIRUS, #no virus
334 - "3"=> AV_VIRUS_FOUND, #virus found
335 - "6"=> AV_VIRUS_FOUND, #virus found
336 - "*"=> AV_SCAN_FAILED, #else scan failed
 332+ 'codemap' => array (
 333+ "0" => AV_NO_VIRUS, # no virus
 334+ "3" => AV_VIRUS_FOUND, # virus found
 335+ "6" => AV_VIRUS_FOUND, # virus found
 336+ "*" => AV_SCAN_FAILED, # else scan failed
337337 ),
338338
339 - 'messagepattern'=> '/.*?Infection:(.*)$/m',
 339+ 'messagepattern' => '/.*?Infection:(.*)$/m',
340340 ),
341341 );
342342
Index: trunk/phase3/includes/LogPage.php
@@ -79,20 +79,24 @@
8080 # And update recentchanges
8181 if ( $this->updateRecentChanges ) {
8282 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
83 - $rcComment = $this->actionText;
84 - if( '' != $this->comment ) {
85 - if ($rcComment == '')
86 - $rcComment = $this->comment;
87 - else
88 - $rcComment .= ': ' . $this->comment;
89 - }
90 -
 83+ $rcComment = $this->getRcComment();
9184 RecentChange::notifyLog( $now, $titleObj, $wgUser, $rcComment, '',
9285 $this->type, $this->action, $this->target, $this->comment, $this->params );
9386 }
9487 return true;
9588 }
9689
 90+ public function getRcComment() {
 91+ $rcComment = $this->actionText;
 92+ if( '' != $this->comment ) {
 93+ if ($rcComment == '')
 94+ $rcComment = $this->comment;
 95+ else
 96+ $rcComment .= ': ' . $this->comment;
 97+ }
 98+ return $rcComment;
 99+ }
 100+
97101 /**
98102 * @static
99103 */

Follow-up revisions

RevisionCommit summaryAuthorDate
r23039Merged revisions 22967-23037 via svnmerge from...david20:15, 16 June 2007
r23099Fix regression introduced in r23023; use the right function name when calling...brion15:11, 19 June 2007
r23104Merged revisions 23087-23102 via svnmerge from...david21:40, 19 June 2007

Status & tagging log