<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rob Rosenbaum's Development Blog &#187; Flash</title>
	<atom:link href="http://robrosenbaum.com/tags/flash/feed/" rel="self" type="application/rss+xml" />
	<link>http://robrosenbaum.com</link>
	<description>PHP, Symfony, and Other Web Things</description>
	<lastBuildDate>Wed, 30 Jan 2008 02:38:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using Flash Upload with PHP &amp; symfony</title>
		<link>http://robrosenbaum.com/php/using-flash-upload-with-php-symfony/</link>
		<comments>http://robrosenbaum.com/php/using-flash-upload-with-php-symfony/#comments</comments>
		<pubDate>Tue, 04 Sep 2007 22:50:09 +0000</pubDate>
		<dc:creator>Rob Rosenbaum</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://robrosenbaum.com/flash/using-flash-upload-with-php-symfony/</guid>
		<description><![CDATA[Using Flash-based multi-file uploads with session cookies.]]></description>
			<content:encoded><![CDATA[<p>Through Flash's <a href="http://livedocs.adobe.com/flex/201/langref/flash/net/FileReference.html"><code class="ActionScript">FileReference</code></a> and <a href="http://livedocs.adobe.com/flex/201/langref/flash/net/FileReferenceList.html"><code class="ActionScript">FileReferenceList</code></a> classes, you  can create a powerful file uploader that allows the user to upload multiple files with a single form element. But beware: unless the user happens to be using IE, the <code class="ActionScript">upload</code> will use a new browser session to upload the files. This means that if you require that a user be authenticated before uploading something (and you better be), the upload won't work - the request will be forwarded to the login form, or to wherever your system forwards unauthorized requests. This is a maddening bug to track down, and there is nothing you can do to make Flash use the right session. The work around is to send the session cookie in the url and, on the server side, use that to override the new (and wrong) session cookie sent by Flash. Here's how that works in symfony, although much of the following is useful for other languages or frameworks:</p>
<p>First, we have to tell our Flash component what the cookie is, so it can roll it into the URL. One solution would be to pass the session cookie as an argument in <a href="http://www.permadi.com/tutorial/flashVars/">FlashVars</a>, but then the user's session cookie is sitting unencrypted in the HTML, leaving them vulnerable to <a href="http://shiflett.org/articles/cross-site-request-forgeries">cross-site request forgery</a>. Better to use javascript to fetch the cookie, and <em>then</em> put it in FlashVars. If you are using <a href="http://www.bobbyvandersluis.com/ufo/">ufo.js</a>, the first argument to <code class="javascript">UFO.create()</code> should look like this:</p>
<pre class="javascript">
{
  movie: '/flash/uploader.swf', 
  id: 'uploader',
  name: 'uploader',

  flashvars: 'cookie=' + document.cookie,

  // other options ...
}
</pre>
<p>Note that if you are dealing with multilple cookies, you will want to parse the output of <code class="javascript">document.cookie</code> and send only the desired cookie.</p>
<p class="leadingnoindent">Next, add the cookie to the URL in your ActionScript (this is for ActionScript 2.0):</p>
<pre class="ActionScript2">
var list:Array = myFileRefList.fileList;
var item:FileReference;
var url:String = _root.uploadURL + '?cookie=' + _root.cookie;

for (var i:Number = 0; i < list.length; i++) {
  item.upload (url);
}
</pre>
<p class="leadingnoindent">That does it for the client side. Now, we need to tell PHP to use our cookie instead of the one the browser sent. This does the trick:</p>
<pre class="PHP">
list($cookieName, $cookieValue) = str_split('=', $_GET['cookie']);

session_name($cookieName);
session_id($cookieValue);

session_start();
</pre>
<p>If you are using symfony, things are a little more complex. We need to call <code class="PHP">session_name()</code> and <code class="PHP">session_id()</code> <em>before</em> <code class="PHP">session_start()</code>; looking at the symfony source code, we find that <code class="PHP">session_start()</code> is called in <code class="PHP">sfSessionStorage::initialize()</code>. So a simple solution is to extend the sfSessionStorage class:</p>
<pre class="PHP">
class mySessionStorage extends sfSessionStorage
{
  public function initialize($context, $parameters = null)
  {
    if ( /* whatever the condition is when we want to do this */ ) {
      if ($cookie = $context->getRequest()->getParameter('cookie')) {
        $name = 'symfony';
        preg_match('/^' . $name.'=(.*)$/', $cookie, $asMatch);
        $value = $asMatch[1];

        session_name($name);
        session_id($value);
      }
    }

    parent::initialize($context, $parameters);
  }
}
</pre>
<p class="leadingnoindent">Finally, tell symfony to use the mySessionStorage class by editting factories.yml:</p>
<pre class="YAML">
all:
  storage:
    class: mySessionStorage
    param:
      session_name: symfony
</pre>
<p class="leadingnoindent">And you're done! Clear your cache, and try it out. An easy way to check if it's working is to add the following line to the end of index.php (or frontend.php):</p>
<pre class="PHP">file_put_contents('testSessionOverwrite.txt', sfContext::getInstance()->getRequest()->getActionName());</pre>
<p>Now try uploading a file. If the action name in testSessionOverwrite.txt is the action you're uploading to, you're golden. If instead it is the name of the action that authenticates users, you have a problem somewhere, and you get to have the enjoyable experience of debugging PHP without browser output. Remember to erase the debugging line from your front controller when you get everything working.</p>
<p>Next time, just make the users upload their damn files one-at-a-time...</p>
]]></content:encoded>
			<wfw:commentRss>http://robrosenbaum.com/php/using-flash-upload-with-php-symfony/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
