Completed
Push — master ( 239c78...0c4744 )
by Fabio
21:35 queued 09:37
created

THttpResponse::ensureHttpHeaderSent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * THttpResponse class
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @copyright Copyright &copy; 2005-2016 The PRADO Group
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 * @package Prado\Web
10
 */
11
12
namespace Prado\Web;
13
use Prado\Exceptions\TInvalidDataValueException;
14
use Prado\Exceptions\TInvalidOperationException;
15
use Prado\Prado;
16
use Prado\TPropertyValue;
17
18
/**
19
 * THttpResponse class
20
 *
21
 * THttpResponse implements the mechanism for sending output to client users.
22
 *
23
 * To output a string to client, use {@link write()}. By default, the output is
24
 * buffered until {@link flush()} is called or the application ends. The output in
25
 * the buffer can also be cleaned by {@link clear()}. To disable output buffering,
26
 * set BufferOutput property to false.
27
 *
28
 * To send cookies to client, use {@link getCookies()}.
29
 * To redirect client browser to a new URL, use {@link redirect()}.
30
 * To send a file to client, use {@link writeFile()}.
31
 *
32
 * By default, THttpResponse is registered with {@link TApplication} as the
33
 * response module. It can be accessed via {@link TApplication::getResponse()}.
34
 *
35
 * THttpResponse may be configured in application configuration file as follows
36
 *
37
 * <module id="response" class="System.Web.THttpResponse" CacheExpire="20" CacheControl="nocache" BufferOutput="true" />
38
 *
39
 * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
40
 * and {@link getBufferOutput BufferOutput} are optional properties of THttpResponse.
41
 *
42
 * THttpResponse sends charset header if either {@link setCharset() Charset}
43
 * or {@link TGlobalization::setCharset() TGlobalization.Charset} is set.
44
 *
45
 * Since 3.1.2, HTTP status code can be set with the {@link setStatusCode StatusCode} property.
46
 *
47
 * Note: Some HTTP Status codes can require additional header or body information. So, if you use {@link setStatusCode StatusCode}
48
 * in your application, be sure to add theses informations.
49
 * E.g : to make an http authentication :
50
 * <code>
51
 *  public function clickAuth ($sender, $param)
52
 *  {
53
 *     $response=$this->getResponse();
54
 *     $response->setStatusCode(401);
55
 *     $response->appendHeader('WWW-Authenticate: Basic realm="Test"');
56
 *  }
57
 * </code>
58
 *
59
 * This event handler will sent the 401 status code (Unauthorized) to the browser, with the WWW-Authenticate header field. This
60
 * will force the browser to ask for a username and a password.
61
 *
62
 * @author Qiang Xue <[email protected]>
63
 * @package Prado\Web
64
 * @since 3.0
65
 */
66
class THttpResponse extends \Prado\TModule implements \Prado\IO\ITextWriter
67
{
68
	const DEFAULT_CONTENTTYPE	= 'text/html';
69
	const DEFAULT_CHARSET		= 'UTF-8';
70
71
	/**
72
	 * @var The differents defined status code by RFC 2616 {@link http://www.faqs.org/rfcs/rfc2616}
73
	 */
74
	private static $HTTP_STATUS_CODES = array(
75
		100 => 'Continue', 101 => 'Switching Protocols',
76
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
77
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
78
		400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
79
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
80
	);
81
82
	/**
83
	 * @var boolean whether to buffer output
84
	 */
85
	private $_bufferOutput=true;
86
	/**
87
	 * @var boolean if the application is initialized
88
	 */
89
	private $_initialized=false;
90
	/**
91
	 * @var THttpCookieCollection list of cookies to return
92
	 */
93
	private $_cookies=null;
94
	/**
95
	 * @var integer response status code
96
	 */
97
	private $_status=200;
98
	/**
99
	 * @var string reason correspond to status code
100
	 */
101
	private $_reason='OK';
102
	/**
103
	 * @var string HTML writer type
104
	 */
105
	private $_htmlWriterType='\Prado\Web\UI\THtmlWriter';
106
	/**
107
	 * @var string content type
108
	 */
109
	private $_contentType=null;
110
	/**
111
	 * @var string|boolean character set, e.g. UTF-8 or false if no character set should be send to client
112
	 */
113
	private $_charset='';
114
	/**
115
	 * @var THttpResponseAdapter adapter.
116
	 */
117
	private $_adapter;
118
	/**
119
	 * @var boolean whether http response header has been sent
120
	 */
121
	private $_httpHeaderSent;
122
	/**
123
	 * @var boolean whether content-type header has been sent
124
	 */
125
	private $_contentTypeHeaderSent;
126
127
	/**
128
	 * Destructor.
129
	 * Flushes any existing content in buffer.
130
	 */
131
	public function __destruct()
132
	{
133
		//if($this->_bufferOutput)
134
		//	@ob_end_flush();
135
	}
136
137
	/**
138
	 * @param THttpResponseAdapter response adapter
139
	 */
140
	public function setAdapter(THttpResponseAdapter $adapter)
141
	{
142
		$this->_adapter=$adapter;
143
	}
144
145
	/**
146
	 * @return THttpResponseAdapter response adapter, null if not exist.
147
	 */
148
	public function getAdapter()
149
	{
150
		return $this->_adapter;
151
	}
152
153
	/**
154
	 * @return boolean true if adapter exists, false otherwise.
155
	 */
156
	public function getHasAdapter()
157
	{
158
		return $this->_adapter!==null;
159
	}
160
161
	/**
162
	 * Initializes the module.
163
	 * This method is required by IModule and is invoked by application.
164
	 * It starts output buffer if it is enabled.
165
	 * @param TXmlElement module configuration
166
	 */
167
	public function init($config)
168
	{
169
		if($this->_bufferOutput)
170
			ob_start();
171
		$this->_initialized=true;
172
		$this->getApplication()->setResponse($this);
173
	}
174
175
	/**
176
	 * @return integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter. Defaults to 180.
177
	 */
178
	public function getCacheExpire()
179
	{
180
		return session_cache_expire();
181
	}
182
183
	/**
184
	 * @param integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter.
185
	 */
186
	public function setCacheExpire($value)
187
	{
188
		session_cache_expire(TPropertyValue::ensureInteger($value));
189
	}
190
191
	/**
192
	 * @return string cache control method to use for session pages
193
	 */
194
	public function getCacheControl()
195
	{
196
		return session_cache_limiter();
197
	}
198
199
	/**
200
	 * @param string cache control method to use for session pages. Valid values
201
	 *               include none/nocache/private/private_no_expire/public
202
	 */
203
	public function setCacheControl($value)
204
	{
205
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
206
	}
207
208
	/**
209
	 * @return string content type, default is text/html
210
	 */
211
	public function setContentType($type)
212
	{
213
		if ($this->_contentTypeHeaderSent)
214
			throw new \Exception('Unable to alter content-type as it has been already sent');
215
		$this->_contentType = $type;
216
	}
217
218
	/**
219
	 * @return string current content type
220
	 */
221
	public function getContentType()
222
	{
223
		return $this->_contentType;
224
	}
225
226
	/**
227
	 * @return string|boolean output charset.
228
	 */
229
	public function getCharset()
230
	{
231
		return $this->_charset;
232
	}
233
234
	/**
235
	 * @param string|boolean output charset.
236
	 */
237
	public function setCharset($charset)
238
	{
239
		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
240
	}
241
242
	/**
243
	 * @return boolean whether to enable output buffer
244
	 */
245
	public function getBufferOutput()
246
	{
247
		return $this->_bufferOutput;
248
	}
249
250
	/**
251
	 * @param boolean whether to enable output buffer
252
	 * @throws TInvalidOperationException if session is started already
253
	 */
254
	public function setBufferOutput($value)
255
	{
256
		if($this->_initialized)
257
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
258
		else
259
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
260
	}
261
262
	/**
263
	 * @return integer HTTP status code, defaults to 200
264
	 */
265
	public function getStatusCode()
266
	{
267
		return $this->_status;
268
	}
269
270
	/**
271
	 * Set the HTTP status code for the response.
272
	 * The code and its reason will be sent to client using the currently requested http protocol version (see {@link THttpRequest::getHttpProtocolVersion})
273
	 * Keep in mind that HTTP/1.0 clients might not understand all status codes from HTTP/1.1
274
	 *
275
	 * @param integer HTTP status code
276
	 * @param string HTTP status reason, defaults to standard HTTP reasons
277
	 */
278
	public function setStatusCode($status, $reason=null)
279
	{
280
		if ($this->_httpHeaderSent)
281
			throw new \Exception('Unable to alter response as HTTP header already sent');
282
		$status=TPropertyValue::ensureInteger($status);
283
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
284
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
285
		}else{
286
			if($reason===null || $reason==='') {
287
				throw new TInvalidDataValueException("response_status_reason_missing");
288
			}
289
			$reason=TPropertyValue::ensureString($reason);
290
			if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($reason, ' ') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($reason, ' ') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
291
				throw new TInvalidDataValueException("response_status_reason_barchars");
292
			}
293
			$this->_reason=$reason;
294
		}
295
		$this->_status=$status;
296
	}
297
298
	/**
299
	 * @param string HTTP status reason
300
	 */
301
	public function getStatusReason() {
302
		return $this->_reason;
303
	}
304
305
	/**
306
	 * @return THttpCookieCollection list of output cookies
307
	 */
308
	public function getCookies()
309
	{
310
		if($this->_cookies===null)
311
			$this->_cookies=new THttpCookieCollection($this);
312
		return $this->_cookies;
313
	}
314
315
	/**
316
	 * Outputs a string.
317
	 * It may not be sent back to user immediately if output buffer is enabled.
318
	 * @param string string to be output
319
	 */
320
	public function write($str)
321
	{
322
		// when starting output make sure we send the headers first
323
		if (!$this->_bufferOutput and !$this->_httpHeaderSent)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
324
			$this->ensureHeadersSent();
325
		echo $str;
326
	}
327
328
	/**
329
	 * Sends a file back to user.
330
	 * Make sure not to output anything else after calling this method.
331
	 * @param string file name
332
	 * @param string content to be set. If null, the content will be read from the server file pointed to by $fileName.
333
	 * @param string mime type of the content.
334
	 * @param array list of headers to be sent. Each array element represents a header string (e.g. 'Content-Type: text/plain').
335
	 * @param boolean force download of file, even if browser able to display inline. Defaults to 'true'.
336
	 * @param string force a specific file name on client side. Defaults to 'null' means auto-detect.
337
	 * @param integer size of file or content in bytes if already known. Defaults to 'null' means auto-detect.
338
	 * @throws TInvalidDataValueException if the file cannot be found
339
	 */
340
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
341
	{
342
		static $defaultMimeTypes=array(
343
			'css'=>'text/css',
344
			'gif'=>'image/gif',
345
			'png'=>'image/png',
346
			'jpg'=>'image/jpeg',
347
			'jpeg'=>'image/jpeg',
348
			'htm'=>'text/html',
349
			'html'=>'text/html',
350
			'js'=>'javascript/js',
351
			'pdf'=>'application/pdf',
352
			'xls'=>'application/vnd.ms-excel',
353
		);
354
355
		if($mimeType===null)
356
		{
357
			$mimeType='text/plain';
358
			if(function_exists('mime_content_type'))
359
				$mimeType=mime_content_type($fileName);
360
			else if(($ext=strrchr($fileName,'.'))!==false)
361
			{
362
				$ext=substr($ext,1);
363
				if(isset($defaultMimeTypes[$ext]))
364
					$mimeType=$defaultMimeTypes[$ext];
365
			}
366
		}
367
368
		if($clientFileName===null)
369
			$clientFileName=basename($fileName);
370
		else
371
			$clientFileName=basename($clientFileName);
372
373
		if($fileSize===null || $fileSize < 0)
374
			$fileSize = ($content===null?filesize($fileName):strlen($content));
375
376
		$this->sendHttpHeader();
377
		if(is_array($headers))
378
		{
379
			foreach($headers as $h)
380
				header($h);
381
		}
382
		else
383
		{
384
			header('Pragma: public');
385
			header('Expires: 0');
386
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
387
			header("Content-Type: $mimeType");
388
			$this->_contentTypeHeaderSent = true;
389
		}
390
391
		header('Content-Length: '.$fileSize);
392
		header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
393
		header('Content-Transfer-Encoding: binary');
394
		if($content===null)
395
			readfile($fileName);
396
		else
397
			echo $content;
398
	}
399
400
	/**
401
	 * Redirects the browser to the specified URL.
402
	 * The current application will be terminated after this method is invoked.
403
	 * @param string URL to be redirected to. If the URL is a relative one, the base URL of
404
	 * the current request will be inserted at the beginning.
405
	 */
406
	public function redirect($url)
407
	{
408
		if($this->getHasAdapter())
409
			$this->_adapter->httpRedirect($url);
410
		else
411
			$this->httpRedirect($url);
412
	}
413
414
	/**
415
	 * Redirect the browser to another URL and exists the current application.
416
	 * This method is used internally. Please use {@link redirect} instead.
417
	 *
418
	 * @since 3.1.5
419
	 * You can set the set {@link setStatusCode StatusCode} to a value between 300 and 399 before
420
	 * calling this function to change the type of redirection.
421
	 * If not specified, StatusCode will be 302 (Found) by default
422
	 *
423
	 * @param string URL to be redirected to. If the URL is a relative one, the base URL of
424
	 * the current request will be inserted at the beginning.
425
	 */
426
	public function httpRedirect($url)
427
	{
428
		$this->ensureHeadersSent();
429
430
		// Under IIS, explicitly send an HTTP response including the status code
431
		// this is handled automatically by PHP on Apache and others
432
		$isIIS = (stripos($this->getRequest()->getServerSoftware(), "microsoft-iis") !== false);
433
		if($url[0]==='/')
434
			$url=$this->getRequest()->getBaseUrl().$url;
435
		if ($this->_status >= 300 && $this->_status < 400)
436
		{
437
			// The status code has been modified to a valid redirection status, send it
438
			if($isIIS)
439
			{
440
				header('HTTP/1.1 ' . $this->_status . ' ' . self::$HTTP_STATUS_CODES[
441
					array_key_exists($this->_status, self::$HTTP_STATUS_CODES)
442
						? $this->_status
443
						: 302
444
					]);
445
			}
446
			header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
447
		} else {
448
			if($isIIS)
449
				header('HTTP/1.1 302 '.self::$HTTP_STATUS_CODES[302]);
450
			header('Location: '.str_replace('&amp;','&',$url));
451
		}
452
453
		if(!$this->getApplication()->getRequestCompleted())
454
			$this->getApplication()->onEndRequest();
455
456
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method httpRedirect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
457
	}
458
459
	/**
460
	 * Reloads the current page.
461
	 * The effect of this method call is the same as user pressing the
462
	 * refresh button on his browser (without post data).
463
	 **/
464
	public function reload()
465
	{
466
		$this->redirect($this->getRequest()->getRequestUri());
467
	}
468
469
	/**
470
	 * Flush the response contents and headers.
471
	 */
472
	public function flush($continueBuffering = true)
473
	{
474
		if($this->getHasAdapter())
475
			$this->_adapter->flushContent($continueBuffering);
476
		else
477
			$this->flushContent($continueBuffering);
478
	}
479
480
	/**
481
	 * Ensures that HTTP response and content-type headers are sent
482
	 */
483
	public function ensureHeadersSent()
484
	{
485
		$this->ensureHttpHeaderSent();
486
		$this->ensureContentTypeHeaderSent();
487
	}
488
489
	/**
490
	 * Outputs the buffered content, sends content-type and charset header.
491
	 * This method is used internally. Please use {@link flush} instead.
492
	 * @param boolean whether to continue buffering after flush if buffering was active
493
	 */
494
	public function flushContent($continueBuffering = true)
495
	{
496
		Prado::trace("Flushing output",'Prado\Web\THttpResponse');
497
		$this->ensureHeadersSent();
498
		if($this->_bufferOutput)
499
		{
500
			// avoid forced send of http headers (ob_flush() does that) if there's no output yet
501
			if (ob_get_length()>0)
502
			{
503
				if (!$continueBuffering)
504
				{
505
					$this->_bufferOutput = false;
506
					ob_end_flush();
507
				}
508
				else
509
					ob_flush();
510
				flush();
511
			}
512
		}
513
		else
514
			flush();
515
	}
516
517
	/**
518
	 * Ensures that the HTTP header with the status code and status reason are sent
519
	 */
520
	protected function ensureHttpHeaderSent()
521
	{
522
		if (!$this->_httpHeaderSent)
523
			$this->sendHttpHeader();
524
	}
525
526
	/**
527
	 * Send the HTTP header with the status code (defaults to 200) and status reason (defaults to OK)
528
	 */
529
	protected function sendHttpHeader()
530
	{
531
		$protocol=$this->getRequest()->getHttpProtocolVersion();
532
		if($this->getRequest()->getHttpProtocolVersion() === null)
533
			$protocol='HTTP/1.1';
534
535
		$phpSapiName = substr(php_sapi_name(), 0, 3);
536
		$cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
537
538
		header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
539
540
		$this->_httpHeaderSent = true;
541
	}
542
543
	/**
544
	 * Ensures that the HTTP header with the status code and status reason are sent
545
	 */
546
	protected function ensureContentTypeHeaderSent()
547
	{
548
		if (!$this->_contentTypeHeaderSent)
549
			$this->sendContentTypeHeader();
550
	}
551
552
	/**
553
	 * Sends content type header with optional charset.
554
	 */
555
	protected function sendContentTypeHeader()
556
	{
557
		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
558
		$charset=$this->getCharset();
559
		if($charset === false) {
560
			$this->appendHeader('Content-Type: '.$contentType);
561
			return;
562
		}
563
564
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
565
			$charset=$globalization->getCharset();
566
567
		if($charset==='') $charset = self::DEFAULT_CHARSET;
568
		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
569
570
		$this->_contentTypeHeaderSent = true;
571
	}
572
573
	/**
574
	 * Returns the content in the output buffer.
575
	 * The buffer will NOT be cleared after calling this method.
576
	 * Use {@link clear()} is you want to clear the buffer.
577
	 * @return string output that is in the buffer.
578
	 */
579
	public function getContents()
580
	{
581
		Prado::trace("Retrieving output",'Prado\Web\THttpResponse');
582
		return $this->_bufferOutput?ob_get_contents():'';
583
	}
584
585
	/**
586
	 * Clears any existing buffered content.
587
	 */
588
	public function clear()
589
	{
590
		if($this->_bufferOutput)
591
			ob_clean();
592
		Prado::trace("Clearing output",'Prado\Web\THttpResponse');
593
	}
594
595
	/**
596
	 * @param integer|null Either {@link CASE_UPPER} or {@link CASE_LOWER} or as is null (default)
597
	 * @return array
598
	 */
599
	public function getHeaders($case=null)
600
	{
601
		$result = array();
602
		$headers = headers_list();
603
		foreach($headers as $header) {
604
			$tmp = explode(':', $header);
605
			$key = trim(array_shift($tmp));
606
			$value = trim(implode(':', $tmp));
607
			if(isset($result[$key]))
608
				$result[$key] .= ', ' . $value;
609
			else
610
				$result[$key] = $value;
611
		}
612
613
		if($case !== null)
614
			return array_change_key_case($result, $case);
615
616
		return $result;
617
	}
618
619
	/**
620
	 * Sends a header.
621
	 * @param string header
622
	 * @param boolean whether the header should replace a previous similar header, or add a second header of the same type
623
	 */
624
	public function appendHeader($value, $replace=true)
625
	{
626
		Prado::trace("Sending header '$value'",'Prado\Web\THttpResponse');
627
		header($value, $replace);
628
	}
629
630
	/**
631
	 * Writes a log message into error log.
632
	 * This method is simple wrapper of PHP function error_log.
633
	 * @param string The error message that should be logged
634
	 * @param integer where the error should go
635
	 * @param string The destination. Its meaning depends on the message parameter as described above
636
	 * @param string The extra headers. It's used when the message parameter is set to 1. This message type uses the same internal function as mail() does.
637
	 * @see http://us2.php.net/manual/en/function.error-log.php
638
	 */
639
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
640
	{
641
		error_log($message,$messageType,$destination,$extraHeaders);
642
	}
643
644
	/**
645
	 * Sends a cookie.
646
	 * Do not call this method directly. Operate with the result of {@link getCookies} instead.
647
	 * @param THttpCookie cook to be sent
648
	 */
649
	public function addCookie($cookie)
650
	{
651
		$request=$this->getRequest();
652
		if($request->getEnableCookieValidation())
653
		{
654
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
655
			setcookie(
656
				$cookie->getName(),
657
				$value,
658
				$cookie->getExpire(),
659
				$cookie->getPath(),
660
				$cookie->getDomain(),
661
				$cookie->getSecure(),
662
				$cookie->getHttpOnly()
663
			);
664
		}
665
		else {
666
			setcookie(
667
				$cookie->getName(),
668
				$cookie->getValue(),
669
				$cookie->getExpire(),
670
				$cookie->getPath(),
671
				$cookie->getDomain(),
672
				$cookie->getSecure(),
673
				$cookie->getHttpOnly()
674
			);
675
		}
676
	}
677
678
	/**
679
	 * Deletes a cookie.
680
	 * Do not call this method directly. Operate with the result of {@link getCookies} instead.
681
	 * @param THttpCookie cook to be deleted
682
	 */
683
	public function removeCookie($cookie)
684
	{
685
		setcookie(
686
			$cookie->getName(),
687
			null,
688
			0,
689
			$cookie->getPath(),
690
			$cookie->getDomain(),
691
			$cookie->getSecure(),
692
			$cookie->getHttpOnly()
693
		);
694
	}
695
696
	/**
697
	 * @return string the type of HTML writer to be used, defaults to THtmlWriter
698
	 */
699
	public function getHtmlWriterType()
700
	{
701
		return $this->_htmlWriterType;
702
	}
703
704
	/**
705
	 * @param string the type of HTML writer to be used, may be the class name or the namespace
706
	 */
707
	public function setHtmlWriterType($value)
708
	{
709
		$this->_htmlWriterType=$value;
710
	}
711
712
	/**
713
	 * Creates a new instance of HTML writer.
714
	 * If the type of the HTML writer is not supplied, {@link getHtmlWriterType HtmlWriterType} will be assumed.
715
	 * @param string type of the HTML writer to be created. If null, {@link getHtmlWriterType HtmlWriterType} will be assumed.
716
	 */
717
	public function createHtmlWriter($type=null)
718
	{
719
		if($type===null)
720
			$type=$this->getHtmlWriterType();
721
		if($this->getHasAdapter())
722
			return $this->_adapter->createNewHtmlWriter($type, $this);
723
		else
724
			return $this->createNewHtmlWriter($type, $this);
725
	}
726
727
	/**
728
	 * Create a new html writer instance.
729
	 * This method is used internally. Please use {@link createHtmlWriter} instead.
730
	 * @param string type of HTML writer to be created.
731
	 * @param ITextWriter text writer holding the contents.
732
	 */
733
	public function createNewHtmlWriter($type, $writer)
734
	{
735
		return Prado::createComponent($type, $writer);
736
	}
737
}
738
739