Follow-up to r111091. Dont paste md5 in the code.
[lhc/web/wiklou.git] / includes / filerepo / FSRepo.php
index f1eaf29..22dbdef 100644 (file)
 <?php
-
 /**
- * A repository for files accessible via the local filesystem. Does not support
- * database access or registration.
+ * A repository for files accessible via the local filesystem.
+ *
+ * @file
+ * @ingroup FileRepo
  */
 
-class FSRepo {
-       const DELETE_SOURCE = 1;
-
-       var $directory, $url, $hashLevels, $thumbScriptUrl, $transformVia404;
-       var $descBaseUrl, $scriptDirUrl, $articleUrl, $fetchDescription;
-       var $fileFactory = array( 'UnregisteredLocalFile', 'newFromTitle' );
-
-       function __construct( $info ) {
-               // Required settings
-               $this->name = $info['name'];
-               $this->directory = $info['directory'];
-               $this->url = $info['url'];
-               $this->hashLevels = $info['hashLevels'];
-               $this->transformVia404 = !empty( $info['transformVia404'] );
-
-               // Optional settings
-               foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription', 
-                       'thumbScriptUrl' ) as $var ) 
-               {
-                       if ( isset( $info[$var] ) ) {
-                               $this->$var = $info[$var];
-                       }
-               }
-       }
-
-       /**
-        * Create a new File object from the local repository
-        * @param mixed $title Title object or string
-        * @param mixed $time Time at which the image is supposed to have existed. 
-        *                    If this is specified, the returned object will be an 
-        *                    instance of the repository's old file class instead of
-        *                    a current file. Repositories not supporting version 
-        *                    control should return false if this parameter is set.
-        */
-       function newFile( $title, $time = false ) {
-               if ( !($title instanceof Title) ) {
-                       $title = Title::makeTitleSafe( NS_IMAGE, $title );
-                       if ( !is_object( $title ) ) {
-                               return null;
-                       }
-               }
-               if ( $time ) {
-                       return call_user_func( $this->oldFileFactor, $title, $this, $time );
-               } else {
-                       return call_user_func( $this->fileFactory, $title, $this );
-               }
-       }
-
-       /**
-        * Find an instance of the named file that existed at the specified time
-        * Returns false if the file did not exist. Repositories not supporting 
-        * version control should return false if the time is specified.
-        *
-        * @param mixed $time 14-character timestamp, or false for the current version
-        */
-       function findFile( $title, $time = false ) {
-               $img = $this->newFile( $title );
-               if ( !$img ) {
-                       return false;
-               }
-               if ( $img->exists() && $img->getTimestamp() <= $time ) {
-                       return $img;
-               }
-               $img = $this->newFile( $title, $time );
-               if ( $img->exists() ) {
-                       return $img;
-               }
-       }
-
-       function getRootDirectory() {
-               return $this->directory;
-       }
-
-       function getRootUrl() {
-               return $this->url;
-       }
-
-       function isHashed() {
-               return (bool)$this->hashLevels;
-       }
-
-       function getThumbScriptUrl() {
-               return $this->thumbScriptUrl;
-       }
-
-       function canTransformVia404() {
-               return $this->transformVia404;
-       }
-
-       function getZonePath( $zone ) {
-               switch ( $zone ) {
-                       case 'public':
-                               return $this->directory;
-                       case 'temp':
-                               return "{$this->directory}/temp";
-                       case 'deleted':
-                               return $GLOBALS['wgFileStore']['deleted']['directory'];
-                       default:
-                               return false;
-               }
-       }
-
-       function getZoneUrl( $zone ) {
-               switch ( $zone ) {
-                       case 'public':
-                               return $this->url;
-                       case 'temp':
-                               return "{$this->url}/temp";
-                       case 'deleted':
-                               return $GLOBALS['wgFileStore']['deleted']['url'];
-                       default:
-                               return false;
-               }
-       }
-
-       /**
-        * Get a URL referring to this repository, with the private mwrepo protocol.
-        */
-       function getVirtualUrl( $suffix = false ) {
-               $path = 'mwrepo://';
-               if ( $suffix !== false ) {
-                       $path .= '/' . $suffix;
-               }
-               return $path;
-       }
-
-       /**
-        * Get the local path corresponding to a virtual URL
-        */
-       function resolveVirtualUrl( $url ) {
-               if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
-                       throw new MWException( __METHOD__.': unknown protoocl' );
-               }
-
-               $bits = explode( '/', substr( $url, 9 ), 3 );
-               if ( count( $bits ) != 3 ) {
-                       throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
-               }
-               list( $host, $zone, $rel ) = $bits;
-               if ( $host !== '' ) {
-                       throw new MWException( __METHOD__.": fetching from a foreign repo is not supported" );
-               }
-               $base = $this->getZonePath( $zone );
-               if ( !$base ) {
-                       throw new MWException( __METHOD__.": invalid zone: $zone" );
-               }
-               return $base . '/' . urldecode( $rel );
-       }
-
-       /**
-        * Store a file to a given destination.
-        */
-       function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
-               $root = $this->getZonePath( $dstZone );
-               if ( !$root ) {
-                       throw new MWException( "Invalid zone: $dstZone" );
-               }
-               $dstPath = "$root/$dstRel";
-
-               if ( !is_dir( dirname( $dstPath ) ) ) {
-                       wfMkdirParents( dirname( $dstPath ) );
-               }
-                       
-               if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) {
-                       $srcPath = $this->resolveVirtualUrl( $srcPath );
-               }
-
-               if ( $flags & self::DELETE_SOURCE ) {
-                       if ( !rename( $srcPath, $dstPath ) ) {
-                               return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), 
-                                       wfEscapeWikiText( $dstPath ) );
-                       }
-               } else {
-                       if ( !copy( $srcPath, $dstPath ) ) {
-                               return new WikiErrorMsg( 'filecopyerror', wfEscapeWikiText( $srcPath ),
-                                       wfEscapeWikiText( $dstPath ) );
-                       }
-               }
-               chmod( $dstPath, 0644 );
-               return true;
-       }
-
-       /**
-        * Pick a random name in the temp zone and store a file to it.
-        * Returns the URL, or a WikiError on failure.
-        * @param string $originalName The base name of the file as specified 
-        *     by the user. The file extension will be maintained.
-        * @param string $srcPath The current location of the file.
-        */
-       function storeTemp( $originalName, $srcPath ) {
-               $dstRel = $this->getHashPath( $originalName ) . 
-                       gmdate( "YmdHis" ) . '!' . $originalName;
-               $result = $this->store( $srcPath, 'temp', $dstRel );
-               if ( WikiError::isError( $result ) ) {
-                       return $result;
-               } else {
-                       return $this->getVirtualUrl( "temp/$dstRel" );
-               }
-       }
-
-       function publish( $srcPath, $dstPath, $archivePath, $flags = 0 ) {
-               if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) {
-                       $srcPath = $this->resolveVirtualUrl( $srcPath );
-               }
-               $dstDir = dirname( $dstPath );
-               if ( !is_dir( $dstDir ) ) wfMkdirParents( $dstDir );
-
-               if( is_file( $dstPath ) ) {
-                       $archiveDir = dirname( $archivePath );
-                       if ( !is_dir( $archiveDir ) ) wfMkdirParents( $archiveDir );
-                       wfSuppressWarnings();
-                       $success = rename( $dstPath, $archivePath );
-                       wfRestoreWarnings();
-
-                       if( ! $success ) {
-                               return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $dstPath ),
-                                 wfEscapeWikiText( $archivePath ) );
-                       }
-                       else wfDebug(__METHOD__.": moved file $dstPath to $archivePath\n");
-                       $status = 'archived';
-               }
-               else {
-                       $status = 'new';
-               }
-
-               $error = false;
-               wfSuppressWarnings();
-               if ( $flags & self::DELETE_SOURCE ) {
-                       if ( !rename( $srcPath, $dstPath ) ) {
-                               $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), 
-                               wfEscapeWikiText( $dstPath ) );
-                       }
-               } else {
-                       if ( !copy( $srcPath, $dstPath ) ) {
-                               $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), 
-                                       wfEscapeWikiText( $dstPath ) );
-                       }
-               }
-               wfRestoreWarnings();
-
-               if( $error ) {
-                       return $error;
-               } else {
-                       wfDebug(__METHOD__.": wrote tempfile $srcPath to $dstPath\n");
-               }
-
-               chmod( $dstPath, 0644 );
-               return $status;
-       }
-       
-       /**
-        * Get a relative path including trailing slash, e.g. f/fa/
-        * If the repo is not hashed, returns an empty string
-        */
-       function getHashPath( $name ) {
-               if ( $this->isHashed() ) {
-                       $hash = md5( $name );
-                       $path = '';
-                       for ( $i = 1; $i <= $this->hashLevels; $i++ ) {
-                               $path .= substr( $hash, 0, $i ) . '/';
-                       }
-                       return $path;
-               } else {
-                       return '';
-               }
-       }
-
-       function getName() {
-               return $this->name;
-       }
-
-       /**
-        * Get the file description page base URL, or false if there isn't one.
-        * @private
-        */
-       function getDescBaseUrl() {
-               if ( is_null( $this->descBaseUrl ) ) {
-                       if ( !is_null( $this->articleUrl ) ) {
-                               $this->descBaseUrl = str_replace( '$1', 
-                                       urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':', $this->articleUrl );
-                       } elseif ( !is_null( $this->scriptDirUrl ) ) {
-                               $this->descBaseUrl = $this->scriptDirUrl . '/index.php?title=' . 
-                                       urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':';
-                       } else {
-                               $this->descBaseUrl = false;
-                       }
-               }
-               return $this->descBaseUrl;
-       }
-
-       /**
-        * Get the URL of an image description page. May return false if it is
-        * unknown or not applicable. In general this should only be called by the 
-        * File class, since it may return invalid results for certain kinds of 
-        * repositories. Use File::getDescriptionUrl() in user code.
-        *
-        * In particular, it uses the article paths as specified to the repository
-        * constructor, whereas local repositories use the local Title functions.
-        */
-       function getDescriptionUrl( $name ) {
-               $base = $this->getDescBaseUrl();
-               if ( $base ) {
-                       return $base . wfUrlencode( $name );
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Get the URL of the content-only fragment of the description page. For 
-        * MediaWiki this means action=render. This should only be called by the 
-        * repository's file class, since it may return invalid results. User code 
-        * should use File::getDescriptionText().
-        */
-       function getDescriptionRenderUrl( $name ) {
-               if ( isset( $this->scriptDirUrl ) ) {
-                       return $this->scriptDirUrl . '/index.php?title=' . 
-                               wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) . ':' . $name ) .
-                               '&action=render';
-               } else {
-                       $descBase = $this->getDescBaseUrl();
-                       if ( $descBase ) {
-                               return wfAppendQuery( $descBase . wfUrlencode( $name ), 'action=render' );
-                       } else {
-                               return false;
-                       }
-               }
-       }
-
-       /**
-        * Call a callback function for every file in the repository.
-        * Uses the filesystem even in child classes.
-        */
-       function enumFilesInFS( $callback ) {
-               $numDirs = 1 << ( $this->hashLevels * 4 );
-               for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) {
-                       $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex );
-                       $path = $this->directory;
-                       for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) {
-                               $path .= '/' . substr( $hexString, 0, $hexPos + 1 );
-                       }
-                       if ( !file_exists( $path ) || !is_dir( $path ) ) {
-                               continue;
-                       }
-                       $dir = opendir( $path );
-                       while ( false !== ( $name = readdir( $dir ) ) ) {
-                               call_user_func( $callback, $path . '/' . $name );
-                       }
+/**
+ * A repository for files accessible via the local filesystem.
+ * Does not support database access or registration.
+ * 
+ * This is a mostly a legacy class. New uses should not be added.
+ * 
+ * @ingroup FileRepo
+ * @deprecated since 1.19
+ */
+class FSRepo extends FileRepo {
+       function __construct( array $info ) {
+               if ( !isset( $info['backend'] ) ) {
+                       // B/C settings...
+                       $directory = $info['directory'];
+                       $deletedDir = isset( $info['deletedDir'] )
+                               ? $info['deletedDir']
+                               : false;
+                       $thumbDir = isset( $info['thumbDir'] )
+                               ? $info['thumbDir']
+                               : "{$directory}/thumb";
+                       $fileMode = isset( $info['fileMode'] )
+                               ? $info['fileMode']
+                               : 0644;
+
+                       $repoName = $info['name'];
+                       // Get the FS backend configuration
+                       $backend = new FSFileBackend( array(
+                               'name'           => $info['name'] . '-backend',
+                               'lockManager'    => 'fsLockManager',
+                               'containerPaths' => array(
+                                       "{$repoName}-public"  => "{$directory}",
+                                       "{$repoName}-temp"    => "{$directory}/temp",
+                                       "{$repoName}-thumb"   => $thumbDir,
+                                       "{$repoName}-deleted" => $deletedDir
+                               ),
+                               'fileMode'       => $fileMode,
+                       ) );
+                       // Update repo config to use this backend
+                       $info['backend'] = $backend;
+               }
+
+               parent::__construct( $info );
+
+               if ( !( $this->backend instanceof FSFileBackend ) ) {
+                       throw new MWException( "FSRepo only supports FSFileBackend." );
                }
        }
-
-       /**
-        * Call a callaback function for every file in the repository
-        * May use either the database or the filesystem
-        */
-       function enumFiles( $callback ) {
-               $this->enumFilesInFS( $callback );
-       }
 }
-
-?>