Back to index

moin  1.9.0~rc2
AnyWikiDraw_body.php
Go to the documentation of this file.
00001 <?php
00002 /*
00003  * @(#)AnyWikiDraw_body.php 
00004  *
00005  * Copyright (c) 2007-2008 by the original authors of AnyWikiDraw
00006  * and all its contributors.
00007  * All rights reserved.
00008  *
00009  * The copyright of this software is owned by the authors and  
00010  * contributors of the AnyWikiDraw project ("the copyright holders").
00011  * You may not use, copy or modify this software, except in  
00012  * accordance with the license agreement you entered into with  
00013  * the copyright holders. For details see accompanying license terms. 
00014  */
00015 
00031 include 'SpecialUpload.php';
00032 
00033 class AnyWikiDraw extends SpecialPage {
00037        var $mUploadDescription, $mLicense, $mUploadOldVersion;
00038        var $mUploadCopyStatus, $mUploadSource, $mWatchthis;
00039        
00040        function AnyWikiDraw() {
00041               SpecialPage::SpecialPage("AnyWikiDraw");
00042               self::loadMessages();
00043 
00044               $this->mUploadDescription = '';
00045               $this->mLicense = '';
00046               $this->mUploadCopyStatus = '';
00047               $this->mUploadSource = '';
00048               $this->mWatchthis = false;
00049        }
00050        
00051        function execute( $par ) {
00052               global $wgRequest, $wgOut;
00053               
00054               if ($wgRequest->wasPosted()) {
00055                      $this->processUpload();
00056               } else if (strlen($wgRequest->getVal("image","")) > 0) {
00057                      $this->processDownload();
00058               } else {
00059                      $this->setHeaders();
00060               
00061                      # Get request data from, e.g.
00062                      # $param = $wgRequest->getText('param');
00063                             
00064                      # Show information about AnyWikiDraw
00065             global $wgAnyWikiDrawVersion;
00066                      $wgOut->addWikiText(
00067                             wfMsg('anywikidraw_about', $wgAnyWikiDrawVersion)
00068                      );
00069 
00070             # Check uploading enabled
00071             global $wgEnableUploads, $wgSitename;
00072               if( !$wgEnableUploads ) {
00073                      $wgOut->addWikiText(
00074                             wfMsg('anywikidraw_upload_disabled', $wgSitename)
00075                 );
00076             } 
00077 
00078             # Check file extensions enabled
00079             global $wgFileExtensions;
00080             $requiredExtensions = array("svg","png","jpg");
00081             $missingExtensions = array();
00082             foreach ($requiredExtensions as $ext) {
00083                 if (! in_array($ext, $wgFileExtensions)) {
00084                     $missingExtensions[] = $ext;
00085                 }
00086             }
00087             if (count($missingExtensions) == 1) {
00088                      $wgOut->addWikiText(
00089                             wfMsg('anywikidraw_extension_disabled', $wgSitename, ".".implode(", .", $missingExtensions) )
00090                 );
00091             } else if (count($missingExtensions) > 1) {
00092                      $wgOut->addWikiText(
00093                             wfMsg('anywikidraw_extensions_disabled', $wgSitename, ".".implode(", .", $missingExtensions) )
00094                 );
00095             }
00096               
00097 
00098               
00099                      // Output
00100                      // $wgOut->addHTML( $output );
00101               }
00102        }
00103        
00108        function processUpload() {
00109               global $wgUser, $wgUploadDirectory, $wgRequest;
00110               
00111               $fname= "AnyWikiDraw_body::processUpload";
00112 
00113               // Retrieve form fields
00114               $drawingName = $wgRequest->getText('DrawingName');
00115               $drawingWidth = $wgRequest->getText('DrawingWidth');
00116               $drawingHeight = $wgRequest->getText('DrawingHeight');
00117               $drawingTempFile =  $wgRequest->getFileTempName('DrawingData');
00118               $drawingFileSize = $wgRequest->getFileSize( 'DrawingData' );
00119               $drawingUploadError = $wgRequest->getUploadError('DrawingData');
00120               $renderedTempFile =  $wgRequest->getFileTempName('RenderedImageData');
00121               $renderedFileSize = $wgRequest->getFileSize( 'RenderedImageData' );
00122               $renderedUploadError = $wgRequest->getUploadError('RenderedImageData');
00123               $imageMapTempFile =  $wgRequest->getFileTempName('ImageMapData');
00124               $imageMapFileSize = $wgRequest->getFileSize( 'ImageMapData' );
00125               $imageMapUploadError = $wgRequest->getUploadError('ImageMapData');
00126               $uploadSummary = $wgRequest->getText('UploadSummary');
00127               
00128               // validate image dimension
00129               if (! is_numeric($drawingWidth) || $drawingWidth < 1) {
00130                      $drawingWidth = null;
00131               }
00132               if (! is_numeric($drawingHeight) || $drawingHeight < 1) {
00133                      $drawingHeight = null;
00134               }
00135 
00136               # If there was no filename or no image data, give up quickly.
00137               if (strlen($drawingName) == 0 || $drawingFileSize == 0) {
00138                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00139                                    '[user '.$wgUser->getName().'] '.
00140                                    $fname.' received bad request [DrawingName='.$drawingName.']'.
00141                                    '[fileSize(DrawingData)='.$drawingFileSize.']'
00142                      );
00143                      header('HTTP/1.0 400 Bad Request');
00144                      exit("\n\n"+'<html><body>DrawingName and DrawingData must be supplied.</body></html>');
00145               }
00146 
00147               // Verify filename
00148               # Chop off any directories in the given filename.
00149               $drawingName = wfBaseName($drawingName);
00150               $imageExtension = substr(strrchr($drawingName, '.'), 1);
00151               
00152               # Only allow filenames with known extensions
00153               $allowedExtensions = array('svg', 'svgz', 'png', 'jpg');
00154               if (! in_array($imageExtension, $allowedExtensions)) {
00155                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00156                                    '[user '.$wgUser->getName().'] '.
00157                                    $fname.' Received bad image extension [DrawingName='.$drawingName.']');
00158                      header('HTTP/1.0 400 Bad Request');
00159                      exit("\n\n"+'<html><body>DrawingName must have one of the following extensions: '.
00160                                    implode(',', $allowedExtensions).
00161                             '.</body></html>');
00162               }
00163 
00168               $filtered = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $drawingName );
00169               $nt = Title::newFromText( $filtered );
00170               if( is_null( $nt ) ) {
00171                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00172                                    '[user '.$wgUser->getName().'] '.
00173                                    $fname.' Received bad image name [DrawingName='.$drawingName.']');
00174                      header('HTTP/1.0 400 Bad Request');
00175                      exit("\n\n"+'<html><body>DrawingName must contain legible characters only.</body></html>');
00176               }
00177               $nt =& Title::makeTitle( NS_IMAGE, $nt->getDBkey() );
00178               $uploadSaveName = $nt->getDBkey();
00179               
00180               
00185               if( !$nt->userCanEdit() ) {
00186                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00187                                    '[user '.$wgUser->getName().'] '.
00188                                    $fname.' image is protected [DrawingName='.$drawingName.']');
00189                      header('HTTP/1.0 403 Forbidden');
00190                      exit("\n\n"+'<html><body>You are not allowed to edit this image.</body></html>');
00191               }
00192 
00196               if( !$this->userCanOverwrite($uploadSaveName) ) {
00197                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00198                                    '[user '.$wgUser->getName().'] '.
00199                                    $fname.' image may not be overwritten [DrawingName='.$drawingName.']');
00200                      header('HTTP/1.0 403 Forbidden');
00201                      exit("\n\n"+'<html><body>You are not allowed to overwrite this image.</body></html>');
00202               }
00203               
00205               if( !is_writeable( $wgUploadDirectory ) ) {
00206                      header('HTTP/1.0 403 Forbidden');
00207                      exit("\n\n"+'<html><body>The upload directory on the server is read only.</body></html>');
00208               }
00209               
00213               $archive = wfImageArchiveDir( $uploadSaveName, 'temp' );
00214               
00220               $veri = $this->verify( $drawingTempFile, $imageExtension );
00221               if( $veri !== true ) { 
00222                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00223                                    '[user '.$wgUser->getName().'] '.
00224                                    $fname.' image failed verification [DrawingName='.$drawingName.'][DrawingTempFile='.$drawingTempFile.']');
00225                      unlink($drawingTempFile);
00226                      header('HTTP/1.0 400 Bad Request');
00227                      exit("\n\n"+'<html><body>The image data is corrupt.</body></html>');
00228               }
00229 
00233               $error = '';
00234               if( !wfRunHooks( 'UploadVerification',
00235                             array( $uploadSaveName, $drawingTempFile, &$error ) ) ) {
00236                      wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00237                                    '[user '.$wgUser->getName().'] '.
00238                                    $fname.' image failed extended verification [DrawingName='.$drawingName.']');
00239                      unlink($drawingTempFile);
00240                      header('HTTP/1.0 400 Bad Request');
00241                      exit("\n\n"+'<html><body>The image data does not match the image name extension.</body></html>');
00242               }
00243 
00244        
00249               if( $this->saveUploadedFile( $uploadSaveName,
00250                                            $drawingTempFile,
00251                                            true ) ) {
00256                      $img = Image::newFromName( $uploadSaveName );
00257                      if ($drawingWidth != null) {
00258                             $img->width = $drawingWidth;
00259                      }
00260                      if ($drawingHeight != null) {
00261                             $img->height = $drawingHeight;
00262                      }
00263                      $this->mUploadDescription = $uploadSummary;
00264 
00265                      $success = $img->recordUpload( $this->mUploadOldVersion,
00266                                                      $this->mUploadDescription,
00267                                                      $this->mLicense,
00268                                                      $this->mUploadCopyStatus,
00269                                                      $this->mUploadSource,
00270                                                      $this->mWatchthis );
00271                                                      
00275                       if ($renderedTempFile != null && $drawingWidth != null)
00276                       {
00277                             $thumbName = $img->thumbName($drawingWidth, $img->fromSharedDirectory );
00278                             $thumbDir = wfImageThumbDir( $img->name, $img->fromSharedDirectory );
00279                             $thumbPath = $thumbDir.'/'.$thumbName;
00280                             wfDebug("we have a rendered image: ".$renderedTempFile.' width='.$drawingWidth.' height='.$drawingHeight.' thumbName='.$thumbPath );
00281                             if (!file_exists(dirname($thumbPath))) {
00282                                    mkdir(dirname($thumbPath), 0777, true);
00283                             }
00284                             // Look at the contents of the file; if we can recognize the
00285                             // type but it's corrupt or data of the wrong type, we should
00286                             // probably not accept it.
00287                             $veri = $this->verify( $renderedTempFile, 'png' );
00288                             if( $veri !== true ) { 
00289                                    wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00290                                           '[user '.$wgUser->getName().'] '.
00291                                           $fname.' rendered image failed verification [DrawingName='.$drawingName.'][RenderedTempFile='.$renderedTempFile.']');
00292                                    unlink($renderedTempFile);
00293                             } else {
00294                                    move_uploaded_file($renderedTempFile, $thumbPath);
00295                             }
00296                       } else {
00297                             if ($renderedTempFile!= null) {
00298                                    unlink($renderedTempFile);
00299                             }
00300                       }
00301 
00305                       if ($imageMapTempFile != null && $drawingWidth != null)
00306                       {
00307                             $thumbName = $img->thumbName($drawingWidth, $img->fromSharedDirectory );
00308                             $thumbDir = wfImageThumbDir( $img->name, $img->fromSharedDirectory );
00309                             $imageMapPath = $thumbDir.'/'.$thumbName.'.map';
00310                             wfDebug("we have an image map: ".$imageMapTempFile);
00311                             if (!file_exists(dirname($imageMapPath))) {
00312                                    mkdir(dirname($imageMapPath), 0777, true);
00313                             }
00314                             // Look at the contents of the file; if we can recognize the
00315                             // type but it's corrupt or data of the wrong type, we should
00316                             // probably not accept it.
00317                             $hasScript = $this->detectScript( $imageMapTempFile, 'text/html', 'html' );
00318                             if( $hasScript !== false ) { 
00319                                    wfDebug('[client '.$_SERVER["REMOTE_ADDR"].']'.
00320                                           '[user '.$wgUser->getName().'] '.
00321                                           $fname.' image map failed verification [DrawingName='.$drawingName.'][ImageMapTempFile='.$imageMapTempFile.']');
00322                                    unlink($imageMapTempFile);
00323                             } else {
00324                                    move_uploaded_file($imageMapTempFile, $imageMapPath);
00325                             }
00326                       } else {
00327                             if ($imageMapTempFile!= null) {
00328                                    unlink($imageMapTempFile);
00329                             }
00330                       }
00331 
00332 
00333                      if ( $success ) {
00334                             $this->showSuccess();
00335                             wfRunHooks( 'UploadComplete', array( &$img ) );
00336                      } else {
00337                             // Image::recordUpload() fails if the image went missing, which is
00338                             // unlikely, hence the lack of a specialised message
00339                             $wgOut->showFileNotFoundError( $this->mUploadSaveName );
00340                      }
00341               }
00342               if ($renderedTempFile!= null) {
00343                      unlink($renderedTempFile);
00344               }
00345               if ($imageMapTempFile!= null) {
00346                      unlink($imageMapTempFile);
00347               }
00348        }
00349        
00355        function processDownload() {
00356               global $wgRequest;
00357        
00358               $name = $wgRequest->getVal("image","");
00359               $image = Image::newFromName($name);
00360               $imagePath = $image->getImagePath();
00361               if ($imagePath != null && file_exists($imagePath) && $filehandle=fopen($imagePath,'r')) {
00362                      header('Last-Modified: '.date(DATE_RFC822, filectime($imagePath)));
00363                      header('Cache-Control: no-cache');
00364                      if ($image->getMimeType() == 'image/svg') {
00365                             header('Content-Type: image/svg+xml');
00366                      } else {
00367                             header('Content-Type: '.$image->getMimeType());
00368                      }
00369                      header('Content-Length: '.filesize($imagePath));
00370                      fpassthru($filehandle);
00371                      fclose($filehandle);
00372                      exit;
00373               } else {
00374                      header('HTTP/1.0 404 Not Found');
00375                      echo 'image '.$name.' not found'; // do we need to i18n this? It's never displayed to a user.
00376                      exit;
00377               }
00378        }
00383        function showSuccess() {
00384               header('HTTP/1.0 200 OK');
00385               exit;
00386        }
00387 
00402        function saveUploadedFile( $saveName, $tempName, $useRename = false ) {
00403               global $wgOut, $wgAllowCopyUploads;
00404               
00405               $fname= "SpecialUpload::saveUploadedFile";
00406               
00407               if ( !$useRename && $wgAllowCopyUploads && $this->mSourceType == 'web' ) {
00408                      $useRename = true;
00409               }
00410 
00411               $dest = wfImageDir( $saveName );
00412               $archive = wfImageArchiveDir( $saveName );
00413               if ( !is_dir( $dest ) ) wfMkdirParents( $dest );
00414               if ( !is_dir( $archive ) ) wfMkdirParents( $archive );
00415               
00416               $this->mSavedFile = "{$dest}/{$saveName}";
00417 
00418               if( is_file( $this->mSavedFile ) ) {
00419                      $this->mUploadOldVersion = gmdate( 'YmdHis' ) . "!{$saveName}";
00420                      wfSuppressWarnings();
00421                      $success = rename( $this->mSavedFile, "${archive}/{$this->mUploadOldVersion}" );
00422                      wfRestoreWarnings();
00423 
00424                      if( ! $success ) {
00425                             $wgOut->showFileRenameError( $this->mSavedFile,
00426                               "${archive}/{$this->mUploadOldVersion}" );
00427                             return false;
00428                      }
00429                      else wfDebug("$fname: moved file ".$this->mSavedFile." to ${archive}/{$this->mUploadOldVersion}\n");
00430               }
00431               else {
00432                      $this->mUploadOldVersion = '';
00433               }
00434 
00435               wfSuppressWarnings();
00436               $success = $useRename
00437                      ? rename( $tempName, $this->mSavedFile )
00438                      : move_uploaded_file( $tempName, $this->mSavedFile );
00439               wfRestoreWarnings();
00440 
00441               if( ! $success ) {
00442                      $wgOut->showFileCopyError( $tempName, $this->mSavedFile );
00443                      return false;
00444               } else {
00445                      wfDebug("$fname: wrote tempfile $tempName to ".$this->mSavedFile."\n");
00446               }
00447 
00448               chmod( $this->mSavedFile, 0644 );
00449               return true;
00450        }
00451        
00452        function loadMessages() {
00453               static $messagesLoaded = false;
00454               global $wgMessageCache;
00455               if ( $messagesLoaded ) return;
00456               $messagesLoaded = true;
00457 
00458               require( dirname( __FILE__ ) . '/AnyWikiDraw.i18n.php' );
00459               foreach ( $messages as $lang => $msgs ) {
00460                             $wgMessageCache->addMessages( $msgs, $lang );
00461               }
00462         return true;
00463        }
00464 
00474        function userCanOverwrite( $name ) {
00475               $img = Image::newFromName( $name );
00476               if( is_null( $img ) ) {
00477                      // Uh... this shouldn't happen ;)
00478                      // But if it does, fall through to previous behavior
00479                      return false;
00480               }
00481 
00482               if( $img->exists() ) {
00483                      global $wgUser, $wgOut;
00484                      if( $img->isLocal() ) {
00485                             if( !$wgUser->isAllowed( 'reupload' ) ) {
00486                                    return false;
00487                             }
00488                      } else {
00489                             if( !$wgUser->isAllowed( 'reupload' ) ||
00490                                 !$wgUser->isAllowed( 'reupload-shared' ) ) {
00491                                 return false;
00492                             }
00493                      }
00494               }
00495 
00496               // Rockin', go ahead and upload
00497               return true;
00498        }
00499        
00507        function verify( $tmpfile, $extension ) {
00508               $fname= "AnyWikiDraw_body::verify";
00509               
00510               #magically determine mime type
00511               // BEGIN PATCH MediaWiki 1.7.1
00512               //$magic=& MimeMagic::singleton();
00513               //$mime= $magic->guessMimeType($tmpfile,false);
00514               $magic=& wfGetMimeMagic();
00515               $mime= $magic->guessMimeType($tmpfile,false);
00516               // END PATCH MediaWiki 1.7.1
00517 
00518               #check mime type, if desired
00519               global $wgVerifyMimeType;
00520               if ($wgVerifyMimeType) {
00521 
00522                      #check mime type against file extension
00523                      if( !$this->verifyExtension( $mime, $extension ) ) {
00524                             //return new WikiErrorMsg( 'uploadcorrupt' );
00525                             return false;
00526                      }
00527                      /*
00528                      #check mime type blacklist
00529                      global $wgMimeTypeBlacklist;
00530                      if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist)
00531                             && $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
00532                             //return new WikiErrorMsg( 'badfiletype', htmlspecialchars( $mime ) );
00533                             wfDebug($fname.' badfiletype');
00534                             return false;
00535                      }*/
00536               }
00537 
00538               #check for htmlish code and javascript
00539               if( $this->detectScript ( $tmpfile, $mime, $extension ) ) {
00540                      //return new WikiErrorMsg( 'uploadscripted' );
00541                             wfDebug($fname.' uploadscripted');
00542                      return false;
00543               }
00544 
00548               $virus= $this->detectVirus($tmpfile);
00549               if ( $virus ) {
00550                      //return new WikiErrorMsg( 'uploadvirus', htmlspecialchars($virus) );
00551                             wfDebug($fname.' uploadvirus');
00552                      return false;
00553               }
00554 
00555               //wfDebug( "$fname: all clear; passing.\n" );
00556               return true;
00557        }
00565        function verifyExtension( $mime, $extension ) {
00566               return UploadForm::verifyExtension($mime, $extension);
00567        }
00577        function detectScript($file, $mime, $extension) {
00578               return UploadForm::detectScript($file, $mime, $extension);
00579        }
00589        function detectVirus($file) {
00590               return UploadForm::detectVirus($file);
00591        }
00592 }
00593 ?>