http://www.mediawiki.org/wiki/Special:Code/MediaWiki/73846

Revision: 73846
Author:   neilk
Date:     2010-09-28 00:28:36 +0000 (Tue, 28 Sep 2010)

Log Message:
-----------
thanks for losing my version history, svn

Added Paths:
-----------
    branches/uploadwizard/phase3/includes/upload/SessionStash.php

Added: branches/uploadwizard/phase3/includes/upload/SessionStash.php
===================================================================
--- branches/uploadwizard/phase3/includes/upload/SessionStash.php               
                (rev 0)
+++ branches/uploadwizard/phase3/includes/upload/SessionStash.php       
2010-09-28 00:28:36 UTC (rev 73846)
@@ -0,0 +1,327 @@
+<?php
+/** 
+ * SessionStash is intended to accomplish a few things:
+ *   - enable applications to temporarily stash files without publishing them 
to the wiki.
+ *      - Several parts of MediaWiki do this in similar ways: UploadBase, 
UploadWizard, and FirefoggChunkedExtension
+ *        the idea is to unify them all here
+ *   - enable applications to find said files later, as long as the session or 
temp files haven't been purged. 
+ *   - enable the uploading user (and *ONLY* the uploading user) to access 
said files, and thumbnails of said files, via a URL.
+ *     We accomplish this by making the session serve as a URL->file mapping, 
on the assumption that nobody else can access 
+ *     the session, even the uploading user.
+ */
+
+class SessionStash {
+       // repository that this uses to store temp files
+       protected $repo; 
+       
+       // array of initialized objects obtained from session (lazily 
initialized upon getFile())
+       private $files = array();  
+
+       // the base URL for files in the stash
+       private $baseUrl;
+       
+       // TODO: Once UploadBase starts using this, switch to use these 
constants rather than UploadBase::SESSION*
+       // const SESSION_VERSION = 2;
+       // const SESSION_KEYNAME = 'wsUploadData';
+
+       /**
+        * Represents the session which contain temporarily stored files.
+        * Designed to be compatible with the session stashing code in 
UploadBase (should replace eventually)
+        * @param {FileRepo} optional -- repo in which to store files. Will 
choose LocalRepo if not supplied.
+        */
+       public function __construct( $repo=null ) { 
+
+               if ( is_null( $repo ) ) {
+                       $repo = RepoGroup::singleton()->getLocalRepo();
+               }
+               $this->repo = $repo;
+
+               if ( ! isset( $_SESSION ) ) {
+                       throw new MWException( 'session not available' );
+               }
+
+               if ( ! array_key_exists( UploadBase::SESSION_KEYNAME, $_SESSION 
) ) {
+                       $_SESSION[UploadBase::SESSION_KEYNAME] = array();
+               }
+               
+               $this->baseUrl = SpecialPage::getTitleFor( 'SessionStash' 
)->getLocalURL(); 
+       }
+
+       public function getBaseUrl() { 
+               return $this->baseUrl;
+       }
+
+       /** 
+        * Get a file from the stash.
+        * May throw exception if session data cannot be parsed due to schema 
change.
+        * @param {Integer} key
+        * @return {null|SessionStashItem} null if no such item, or the item
+        */
+       public function getFile( $key ) { 
+               if ( !array_key_exists( $key, $this->files ) ) {
+                       $stashData = 
$_SESSION[UploadBase::SESSION_KEYNAME][$key];
+
+                       if ($stashData['version'] !== 
UploadBase::SESSION_VERSION ) {
+                               throw new MWException( 'session item schema 
does not match current software' );
+                       }
+                       
+                       // The path is flattened in with the other random props 
so we have to dig it out.
+                       $data = array();
+                       foreach( $stashData as $stashKey => $stashVal ) {
+                               if ( $stashKey === 'mTempPath' ) {
+                                       $path = $stashVal;
+                               } else {
+                                       $data[ $stashKey ] = $stashVal;
+                               }
+                       } 
+                       $this->files[$key] = new SessionStashFile( $this, 
$this->repo, $path, $key, $data );
+               }
+               return $this->files[$key];
+       }
+
+       /**
+        * Stash a file in a temp directory and record that we did this in the 
session, along with other parameters.
+        * @param {String} name - this is used for directory hashing when 
storing. Otherwise not important
+        * @param {String} path - path to file you want stashed
+        * @param {Array} data - other data you want added to the session. Do 
not use 'mTempPath', 'mFileProps', 'mFileSize', or version as keys here
+        * @return {SessionStashFile} file
+        */
+       public function stashFile( $key, $path, $data=array() ) {
+               if ( !$key ) {
+                       $key = mt_rand( 0, 0x7fffffff );
+               }
+
+               // if not already in a temporary area, put it there 
+               $status = $this->repo->storeTemp( basename($path), $path );
+               if( !$status->isOK() ) {
+                       return false;
+               }
+               $stashPath = $status->value;
+
+                
+                // get props
+                $fileProps = File::getPropsFromPath( $path );
+               $fileSize = $fileProps['size'];
+                               
+               // standard info we always store.
+               // 'mTempPath', 'mFileSize', and 'mFileProps' are arbitrary 
names
+               // chosen for compatibility with UploadBase's way of doing this.
+               $stashData = array( 
+                       'mTempPath' => $stashPath,
+                       'mFileSize' => $fileSize,
+                       'mFileProps' => $fileProps,
+                       'version' => UploadBase::SESSION_VERSION
+               );
+
+               // put extended info into the session (this changes from 
application to application).
+               // UploadWizard wants different things than say 
FirefoggChunkedUpload.
+               foreach ($data as $stashKey => $stashValue) {
+                       if ( !array_key_exists( $stashKey, $data ) ) {
+                               $stashData[$stashKey] = $stashValue;
+                       }
+               }
+
+               $_SESSION[UploadBase::SESSION_KEYNAME][$key] = $stashData;
+               
+               //wfDebug( "SESSION\n=====\n " . print_r( $_SESSION, 1 ) . "\n" 
);
+               
+               return $this->getFile( $key );
+       }
+}
+
+class SessionStashFile extends UnregisteredLocalFile {
+       public $sessionStash;
+       public $sessionKey;
+       public $sessionData;
+       private $urlName;
+
+       /**
+        * A LocalFile wrapper around a file that has been temporarily stashed, 
so we can do things like create thumbnails for it
+        * Arguably UnregisteredLocalFile should be handling its own file repo 
but that class is a bit retarded currently
+        * @param {FileRepo} repository where we should find the path
+        * @param {String} path to file
+        */
+       public function __construct( $stash, $repo, $path, $key, $data ) {
+               $this->sessionStash = $stash;
+               $this->sessionKey = $key;
+               $this->sessionData = $data;
+               if ( $repo->isVirtualUrl( $path ) ) {
+                       $path = $repo->resolveVirtualUrl( $path );      
+               }
+               parent::__construct( false, $repo, $path, false );
+
+               // we will be initializing from some tmpnam files that don't 
have extensions.
+               // most of MediaWiki assumes all uploaded files have good 
extensions. So, we fix this.
+               $this->name = basename( $this->path );
+               $this->setExtension();
+
+       }
+
+       /**
+        * A method needed by the file transforming and scaling routines in 
File.php
+        * We do not necessarily care about doing the description at this point
+        * @return {String} the empty string
+        */
+       public function getDescriptionUrl() {
+               return '';
+       }
+
+       /**
+        * Find or guess extension -- ensuring that our extension matches our 
mime type.
+        * Since these files are constructed from php tempnames they may not 
start off 
+        * with an extension
+        * This does not override getExtension because things like getMimeType 
already call getExtension,
+        * and that results in infinite recursion. So, we preemptively *set* 
the extension so getExtension can find it.
+        * For obvious reasons this should be called as early as possible, as 
part of initialization
+        */
+       public function setExtension() {        
+               // Does this have an extension?
+               $n = strrpos( $this->path, '.' );
+               if ( $n !== false ) {
+                       $extension = $n ? substr( $this->path, $n + 1 ) : '';
+               } else {
+                       // If not, assume that it should be related to the mime 
type of the original file.
+                       //
+                       // This entire thing is backwards -- we *should* just 
create an extension based on 
+                       // the mime type of the transformed file, *after* 
transformation.  But File.php demands 
+                       // to know the name of the transformed file before 
creating it. 
+                       $mimeType = $this->getMimeType();
+                       $extensions = explode( ' ', 
MimeMagic::singleton()->getExtensionsForType( $mimeType ) );
+                       if ( count( $extensions ) ) { 
+                               $extension = $extensions[0];    
+                       }
+               }
+
+               if ( is_null( $extension ) ) {
+                       throw 'cannot determine extension';
+               }
+
+               $this->extension = parent::normalizeExtension( $extension );
+       }
+
+       /**
+        * Get the path for the thumbnail (actually any transformation of this 
file)
+        * The actual argument is the result of thumbName although we seem to 
have 
+        * buggy code elsewhere that expects a boolean 'suffix'
+        *
+        * @param {String|false} name of thumbnail (e.g. "120px-123456.jpg" ), 
or false to just get the path
+        * @return {String} path thumbnail should take on filesystem, or 
containing directory if thumbname is false
+        */
+       public function getThumbPath( $thumbName=false ) { 
+               $path = dirname( $this->path );
+               if ( $thumbName !== false ) {
+                       $path .= "/$thumbName";
+               }
+               return $path;
+       }
+
+       /**
+        * Return the file/url base name of a thumbnail with the specified 
parameters
+        *
+        * @param {Array} $params: handler-specific parameters
+        * @return {String} base name for URL, like '120px-12345.jpg'
+        */
+       function thumbName( $params ) {
+               if ( !$this->getHandler() ) {
+                       return null;
+               }
+               $extension = $this->getExtension();
+               list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( 
$extension, $this->getMimeType(), $params );
+               $thumbName = $this->handler->makeParamString( $params ) . '-' . 
$this->getUrlName();
+               if ( $thumbExt != $extension ) {
+                       $thumbName .= ".$thumbExt";
+               }
+               return $thumbName;
+       }
+
+       /** 
+        * Get a URL to access the thumbnail 
+        * This is required because the model of how files work requires that 
+        * the thumbnail urls be predictable. However, in our model the URL is 
not based on the filename
+        * (that's hidden in the session)
+        *
+        * @param {String} basename of thumbnail file -- however, we don't want 
to use the file exactly
+        * @return {String} URL to access thumbnail, or URL with partial path
+        */
+       public function getThumbUrl( $thumbName=false ) { 
+               $path = $this->sessionStash->getBaseUrl();
+               $extension = $this->getExtension();
+               if ( $thumbName !== false ) {
+                       $path .= '/' . rawurlencode( $thumbName );
+               }
+               return $path;
+       }
+
+       /** 
+        * The basename for the URL, which we want to not be related to the 
filename.
+        * Will also be used as the lookup key for a thumbnail file.
+        * @param {Array} optional transformation parameters
+        * @return {String} base url name, like '120px-123456.jpg'
+        */
+       public function getUrlName() {
+               if ( ! $this->urlName ) {
+                       $this->urlName = $this->sessionKey . '.' . 
$this->getExtension();
+               }
+               return $this->urlName;
+       }
+
+       /**
+        * Return the URL of the file, if for some reason we wanted to download 
it
+        * We tend not to do this for the original file, but we do want thumb 
icons
+        * @return {String} url
+        */
+       public function getUrl() {
+               if ( !isset( $this->url ) ) {
+                       $this->url = $this->sessionStash->getBaseUrl() . '/' . 
$this->getUrlName();
+               }
+               return $this->url;
+       }
+
+       /**
+        * Parent classes use this method, for no obvious reason, to return the 
path (relative to wiki root, I assume). 
+        * But with this class, the URL is unrelated to the path.
+        *
+        * @return {String} url
+        */
+       public function getFullUrl() { 
+               return $this->getUrl();
+       }
+
+
+       /**
+        * Typically, transform() returns a ThumbnailImage, which you can think 
of as being the exact
+        * equivalent of an HTML thumbnail on Wikipedia. So its URL is the 
full-size file, not the thumbnail's URL.
+        *
+        * Here we override transform() to stash the thumbnail file, and then 
+        * provide a way to get at the stashed thumbnail file to extract 
properties such as its URL
+        *
+        * @param {Array} parameters suitable for File::transform()
+        * @param {Bitmask} flags suitable for File::transform()
+        * @return {ThumbnailImage} with additional File thumbnailFile property
+        */
+       public function transform( $params, $flags=0 ) { 
+
+               // force it to get a thumbnail right away
+               $flags |= self::RENDER_NOW;
+
+               // returns a ThumbnailImage object containing the url and path. 
Note. NOT A FILE OBJECT.
+               $thumb = parent::transform( $params, $flags );
+
+               $key = $this->thumbName($params);
+
+               // remove extension, so it's stored in the session under 
'120px-123456'
+               // this makes it uniform with the other session key for the 
original, '123456'
+               $n = strrpos( $key, '.' );      
+               if ( $n !== false ) {
+                       $key = substr( $key, 0, $n );
+               }
+
+               // stash the thumbnail File, and provide our caller with a way 
to get at its properties
+               $stashedThumbFile = $this->sessionStash->stashFile( $key, 
$thumb->path );
+               $thumb->thumbnailFile = $stashedThumbFile;
+
+               return $thumb;  
+
+       }
+
+}


Property changes on: 
branches/uploadwizard/phase3/includes/upload/SessionStash.php
___________________________________________________________________
Added: svn:eol-style
   + native



_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to