root/fBuffer.php

Revision 830, 6.8 kB (checked in by wbond, 4 months ago)

Fixed ticket #438 - added a check to ensure the zlib extension is installed in gzipped buffering is requested

LineHide Line Numbers
1 <?php
2 /**
3  * Provides a single, simplified interface for [http://php.net/outcontrol output buffering] to prevent nested buffering issues and provide a more logical API
4  *
5  * @copyright  Copyright (c) 2008-2010 Will Bond
6  * @author     Will Bond [wb] <will@flourishlib.com>
7  * @license    http://flourishlib.com/license
8  *
9  * @package    Flourish
10  * @link       http://flourishlib.com/fBuffer
11  *
12  * @version    1.0.0b3
13  * @changes    1.0.0b3  Added a check to ensure the zlib extension is installd when doing gzipped buffering [wb, 2010-05-20]
14  * @changes    1.0.0b2  Added the `$gzip` parameter to ::start() [wb, 2010-05-19]
15  * @changes    1.0.0b   The initial implementation [wb, 2008-03-16]
16  */
17 class fBuffer
18 {
19     // The following constants allow for nice looking callbacks to static methods
20     const erase        = 'fBuffer::erase';
21     const get          = 'fBuffer::get';
22     const isStarted    = 'fBuffer::isStarted';
23     const replace      = 'fBuffer::replace';
24     const reset        = 'fBuffer::reset';
25     const start        = 'fBuffer::start';
26     const startCapture = 'fBuffer::startCapture';
27     const stop         = 'fBuffer::stop';
28     const stopCapture  = 'fBuffer::stopCapture';
29    
30    
31     /**
32     * If output capturing is currently active
33     *
34     * @var boolean
35     */
36     static private $capturing = FALSE;
37    
38     /**
39     * If output buffering has been started
40     *
41     * @var integer
42     */
43     static private $started = FALSE;
44    
45    
46     /**
47     * Erases the output buffer
48     *
49     * @return void
50     */
51     static public function erase()
52     {
53         if (!self::$started) {
54             throw new fProgrammerException(
55                 'The output buffer can not be erased since output buffering has not been started'
56             );
57         }
58         if (self::$capturing) {
59             throw new fProgrammerException(
60                 'Output capturing is currently active and it must be stopped before the buffer can be erased'
61             );
62         }
63         ob_clean();
64     }
65    
66    
67     /**
68     * Returns the contents of output buffer
69     *
70     * @return string  The contents of the output buffer
71     */
72     static public function get()
73     {
74         if (!self::$started) {
75             throw new fProgrammerException(
76                 'The output buffer can not be retrieved because it has not been started'
77             );
78         }
79         if (self::$capturing) {
80             throw new fProgrammerException(
81                 'Output capturing is currently active and it must be stopped before the buffer can be retrieved'
82             );
83         }
84         return ob_get_contents();
85     }
86    
87    
88     /**
89     * Checks if buffering has been started
90     *
91     * @return boolean  If buffering has been started
92     */
93     static public function isStarted()
94     {
95         return self::$started;
96     }
97    
98    
99     /**
100     * Replaces a value in the output buffer
101     *
102     * @param  string $find     The string to find
103     * @param  string $replace  The string to replace
104     * @return void
105     */
106     static public function replace($find, $replace)
107     {
108         if (!self::$started) {
109             throw new fProgrammerException(
110                 'A replacement can not be made since output buffering has not been started'
111             );
112         }
113         if (self::$capturing) {
114             throw new fProgrammerException(
115                 'Output capturing is currently active and it must be stopped before a replacement can be made'
116             );
117         }
118        
119         // ob_get_clean() actually turns off output buffering, so we do it the long way
120         $contents = ob_get_contents();
121         ob_clean();
122        
123         echo str_replace($find, $replace, $contents);
124     }
125    
126    
127     /**
128     * Resets the configuration and buffer of the class
129     *
130     * @internal
131      *
132     * @return void
133     */
134     static public function reset()
135     {
136         if (self::$capturing) {
137             self::stopCapture();   
138         }
139         if (self::$started) {
140             self::erase();
141             self::stop();   
142         }
143     }
144    
145    
146     /**
147     * Starts output buffering
148     *
149     * @param  boolean $gzip  If the buffered output should be gzipped using [http://php.net/ob_gzhandler `ob_gzhandler()`]
150     * @return void
151     */
152     static public function start($gzip=FALSE)
153     {
154         if (self::$started) {
155             throw new fProgrammerException(
156                 'Output buffering has already been started'
157             );
158         }
159         if (self::$capturing) {
160             throw new fProgrammerException(
161                 'Output capturing is currently active and it must be stopped before the buffering can be started'
162             );
163         }
164         if ($gzip && !extension_loaded('zlib')) {
165             throw new fEnvironmentException(
166                 'The PHP %s extension is required for gzipped buffering, however is does not appear to be loaded',
167                 'zlib'
168             );
169         }
170         ob_start($gzip ? 'ob_gzhandler' : NULL);
171         self::$started = TRUE;
172     }
173    
174    
175     /**
176     * Starts capturing output, should be used with ::stopCapture() to grab output from code that does not offer an option of returning a value instead of outputting it
177     *
178     * @return void
179     */
180     static public function startCapture()
181     {
182         if (self::$capturing) {
183             throw new fProgrammerException(
184                 'Output capturing has already been started'
185             );
186         }
187         ob_start();
188         self::$capturing = TRUE;
189     }
190    
191    
192     /**
193     * Stops output buffering, flushing everything to the browser
194     *
195     * @return void
196     */
197     static public function stop()
198     {
199         if (!self::$started) {
200             throw new fProgrammerException(
201                 'Output buffering can not be stopped since it has not been started'
202             );
203         }
204         if (self::$capturing) {
205             throw new fProgrammerException(
206                 'Output capturing is currently active and it must be stopped before buffering can be stopped'
207             );
208         }
209        
210         // Only flush if there is content to push out, otherwise
211         // we might prevent headers from being sent
212         if (ob_get_contents()) {
213             ob_end_flush();
214         } else {
215             ob_end_clean();
216         }
217        
218         self::$started = FALSE;
219     }
220    
221    
222     /**
223     * Stops capturing output, returning what was captured
224     *
225     * @return string  The captured output
226     */
227     static public function stopCapture()
228     {
229         if (!self::$capturing) {
230             throw new fProgrammerException(
231                 'Output capturing can not be stopped since it has not been started'
232             );
233         }
234         self::$capturing = FALSE;
235         return ob_get_clean();
236     }
237    
238    
239     /**
240     * Forces use as a static class
241     *
242     * @return fBuffer
243     */
244     private function __construct() { }
245 }
246  
247  
248  
249 /**
250  * Copyright (c) 2008-2010 Will Bond <will@flourishlib.com>
251  *
252  * Permission is hereby granted, free of charge, to any person obtaining a copy
253  * of this software and associated documentation files (the "Software"), to deal
254  * in the Software without restriction, including without limitation the rights
255  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
256  * copies of the Software, and to permit persons to whom the Software is
257  * furnished to do so, subject to the following conditions:
258  *
259  * The above copyright notice and this permission notice shall be included in
260  * all copies or substantial portions of the Software.
261  *
262  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
263  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
264  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
265  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
266  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
267  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
268  * THE SOFTWARE.
269  */