{"id":2211,"date":"2014-04-17T16:19:43","date_gmt":"2014-04-17T14:19:43","guid":{"rendered":"http:\/\/www.nyamsprod.com\/blog\/?p=2211"},"modified":"2014-04-29T21:54:05","modified_gmt":"2014-04-29T19:54:05","slug":"stream-filtering-with-splfileobject","status":"publish","type":"post","link":"https:\/\/nyamsprod.com\/blog\/stream-filtering-with-splfileobject\/","title":{"rendered":"Stream Filtering with SplFileObject"},"content":{"rendered":"<div class=\"message warning\">\n<p><strong>Attention:<\/strong> Les informations de ce billet sont susceptibles d'&ecirc;tre obsol&egrave;tes car vieux de plus 2 ans.<\/p>\n<p><strong>Warning: <\/strong> The information you are reading may be obsolete, this post was published more than 2 years ago.<\/p>\n<\/div><p>Since PHP4 days, the <a title=\"Understanding Streams in PHP\" href=\"http:\/\/www.sitepoint.com\/%EF%BB%BFunderstanding-streams-in-php\/\">language has been able to interact with streams<\/a>, a resource object that can be read from or written to in a linear fashion. This feature can help us applying filters function on streams while reading from or written to them. This can be interesting if you want, for instance, to compress or decompress, on the fly, a file before or after accessing it.<br \/>\nTo apply those filters, the developer must use PHP stream filtering functions <code>stream_filter_*<\/code> and\/or the php meta wrapper <code>php:\/\/filter<\/code> and have access to a PHP file resource. For instance, any resource returned by <code>fopen<\/code> can be filtered using PHP.<\/p>\n<pre><code class=\"language-php\">$path = 'path\/to\/my\/file.txt';\r\n$fp = fopen($path, 'r');\r\n$filter1 = stream_filter_append($fp, 'string.toupper');\r\n$filter2 = stream_filter_prepend($fp, 'string.rot13', STREAM_FILTER_READ);\r\n$res = fgets($fp); \/\/the output text is ROT13 and then uppercased\r\nstream_filter_remove($filter2);\r\nrewind($fp);\r\n$res = fgets($fp); \/\/the output text is only uppercased<\/code><\/pre>\n<p>The stream filters can be applied when reading,\u00a0 writing or on both actions. They can be removed at any given time. This feature is truly powerful.<!--more--><\/p>\n<p>Now let&#8217;s jump to today&#8217;s post-PHP 5.3+ world where objects like <code>SplFileObject<\/code> where created to offer an OOP approach to file interaction. With the added benefit of using <code>Iterator<\/code> and many other goodies, being able to apply PHP stream filtering features on a <code>SplFileObject<\/code> as easily as on a file resource would be great but that is not currently possible. The main reason being that the <code>SplFileObject<\/code> class does not expose it&#8217;s internal file pointer resource, so <del datetime=\"2014-04-29T19:31:09+00:00\">using any <code>stream_filter_*<\/code> is simply not possible<\/del> adding stream filters to an instantiate <code>SplFileObject<\/code> object is not possible.<\/p>\n<p>If you want to apply stream filters to a <code>SplFileObject<\/code> object, you are required to instantiate the object using the meta wrapper <code>php:\/\/filter<\/code>.<\/p>\n<pre><code class=\"language-php\">$path = 'path\/to\/my\/file.txt';\r\n$file = new SplFileObject('php:\/\/filter\/read=string.rot13|string.toupper\/resource='.$path, 'r');\r\n$file-&gt;fgets();  \/\/the output text is ROT13 and then uppercased<\/code><\/pre>\n<p>This technique works but has several limitations, here are two that come directly in mind:<\/p>\n<ul>\n<li>Writing the PHP meta-wrapper can easily become a headache, if you apply several filters.<\/li>\n<li>the meta wrapper restricts the use of stream filters, as you can not append\/prepend the filters after the object instantiation!!<\/li>\n<li>you can not set the stream filter mode (read and\/or write) on a filter base<\/li>\n<\/ul>\n<p>I understand that the <code>stream_filter_*<\/code> functions were first design to tackle those limitations when using a file resource. It&#8217;s a bit strange that the same problem was re-introduce when <code>SplFileObject<\/code> was designed.<\/p>\n<p>To solve theses issues PHP could expose the internal file pointer resource used by <code>SplFileObject<\/code>, <a title=\"Bug entry to implement file pointer access to SplFileObject\" href=\"https:\/\/bugs.php.net\/bug.php?id=44392\">there&#8217;s a php bug entry for that<\/a>. But I can imagine that exposing the file pointer resource would have some nasty consequences when using the <code>SplFileObject<\/code>. For instance someone could use <code>fclose<\/code> directly on the resource and they&#8217;re maybe worse case scenario.<\/p>\n<p>Another solution would be to implement <code>stream_filter_append<\/code> and <code>stream_filter_prepend<\/code> as new methods for the <code>SplFileObject<\/code>.<\/p>\n<pre><code class=\"language-php\">$file = new SplFileObject('\/path\/to\/my\/file', 'r');\r\n$filter1 = $file-&gt;appendStreamFilter('string.toupper');\r\n$filter2 = $file-&gt;prependStreamFilter('string.rot13', STREAM_FILTER_READ);\r\nstream_filter_remove($filter2);<\/code><\/pre>\n<p>This proposal would be safer to implement, IMHO. <\/p>\n<p>Now don&#8217;t get me wrong, this is not another attempt to go OOP with everything that exists in PHP, but I think I would benefit any codebase that relies heavily on <code>SplFileObject<\/code>, like my PHP CSV manipulation library <a title=\"The CSV Manipulation library\" href=\"http:\/\/csv.thephpleague.com\/\">League\\Csv<\/a>.<\/p>\n<p><strong>Update 2014-04-29:<\/strong> After thinking over this solution a bit, I think there&#8217;s another solution. I think we could implement an new PHP interface called <code>Streamable<\/code> and <code>SplFileObject<\/code> would implement this interface. This interface would act like the <code>Traversable<\/code> interface meaning that it can not be access directly in userland but it would allow classes implementing it to work with functions like <code>stream_filter_append<\/code> and <code>stream_filter_prepend<\/code>. These functions would accept a file resource pointer and\/or a Streamable class. This interface could be use on any PHP function apart from file specific function to allow <code>SplFileObject<\/code> to work on many other situations. It would expose internally only the object file pointer resource to the native functions.<\/p>\n<p>What do you think ?<\/p>\n<p>PS: I don&#8217;t know the amount of code changes, it would require in the PHP source code to implement any of those proposal. But I think something must be done to allow a better use of stream filters with <code>SplFileObject<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>stream filter capabilities and limitations with SplFileObject  in PHP<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5],"tags":[765,412,772,773],"class_list":["post-2211","post","type-post","status-publish","format-standard","hentry","category-web","tag-filtering","tag-php","tag-splfileobject","tag-stream"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/comments?post=2211"}],"version-history":[{"count":5,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2211\/revisions"}],"predecessor-version":[{"id":2246,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/posts\/2211\/revisions\/2246"}],"wp:attachment":[{"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/media?parent=2211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/categories?post=2211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nyamsprod.com\/blog\/wp-json\/wp\/v2\/tags?post=2211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}