Stange string in http response when using php - php

My php code have been working fine. And suddenly i got very strange string in response data.
Every response data is like below.where is "87,0" and"3e,0" come from? How can i get rid of them?(They appears before and after every response data.)
HTTP/1.1 200 OK
Date: Fri, 14 Nov 2014 01:57:40 GMT
Server: Apache
X-Powered-By: PHP/5.4.34
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
87
a:1:{i:0;s:116:"http://www.nytimes.com/2014/09/15/sports/basketball/united-states-wins-fiba-world-cup-title-in-a-rout-of-serbia.html";}
0
HTTP/1.1 200 OK
Date: Fri, 14 Nov 2014 01:57:40 GMT
Server: Apache
X-Powered-By: PHP/5.4.34
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
3e
a:1:{i:0;s:44:"http://www.bbc.com/news/in-pictures-29204063";}
0
foreach($template_arr as $tkey => $template)
{
$keyword = self::getKeyword($template, $typename);
$keyword = urlencode($typename);//encode because it is going to be send through url
$urlPre = self::getURLPre('news');
$urlrule = self::getURLRule($template); //actually it is used in both siteSearch and urlrule,but urlrule seems unnecessary
$s = stream_socket_client("$sochost:$socportno", $errno, $errstr, $soctimeout, STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT);
if ($s)
{
$sockets[$template] = $s;
$out = "GET /DataAC/Search/Search_Bridge_G.php?keyword=$keyword&resultSize=$resultSize&urlPre=$urlPre&urlrule=$urlrule&template=$template";
$out.= " HTTP/1.1\r\n";
$out.= "Connection: Close\r\n";
$out.= "Host:$sochost\r\n\r\n";
fwrite($s, $out);
}
else
{
echo "$errstr ($errno) ,open sock on search keyword # $keyword on template # $tempalte erro when open search bridge.<br/>\n";
}
}
while (count($sockets))
{
$read = $sockets;
$w = null;
$e = null;
stream_select($read, $w, $e, $soctimeout);
if (count($read))
{
/* stream_select generally shuffles $read, so we need to
compute from which socket(s) we're reading. */
foreach($read as $r)
{
$template = array_search($r, $sockets);
$data = fread($r, $convenient_read_block);
// A socket is readable either because it has
// data to read, OR because it's at EOF.
if (strlen($data) == 0)
{
//echo "Template " . $template . " closes at " . date('h:i:s') . "</br>";
$responseData = $result[$template];
echo "!!!!!!!!!!!!!!!$responseData!!!!!!!!!!!!!!!";
$responseArray=unserialize(substr($responseData,strpos($responseData,"\r\n\r\n")+4)); //get serialize array from respose data and unserialize it ,"+4" means we don't need \r\n\r\n
//var_dump($responseArray);
$urlarr = $responseArray;
// assemble result array start
if (!empty($urlarr))
{
$template_url_arr[$template] = $urlarr[0];
$timenow = date('Y-m-d H:i:s', time());
echo "</br>######### Machine search : keyword:#" . $typename . " target url:" . $urlarr[0] . " timestamp: $timenow" . "#########</br>";
}
else
{
echo "</br> ######### Template url arr empty when query keyword #" . $keyword . " under template #" . $template . " #########</br>";
}
// assemble result array end
fclose($r);
unset($sockets[$template]);
}
else
{
if(!isset($result[$template]))//init the array element or there will be a warning
$result[$template]= "";
$result[$template].= $data;
}
}
}
else
{
/* A time-out means that *all* streams have failed
to receive a response. */
echo "Time-out!\n";
break;
}
}
script:Search_Bridge_G.php
require_once '../../global.php';
//require_once('UTIL/MyFileUtil.php');
//require_once('UTIL/MyDocUtil.php');
require_once 'DataAC/Search/GetGSearchLink.php';
error_reporting(E_ALL);
$keyword=$_GET['keyword'];
$keyword=preg_replace('/\s+/', '%20', trim($keyword)); //replace ' ' with %20
$resultSize=$_GET['resultSize'];
$urlPre=$_GET['urlPre'];
$urlrule=$_GET['urlrule'];
$template=$_GET['template'];
$ant = new \DataGenerator\GetLinkG\GetGSearchLink($keyword,$resultSize, $urlPre,$urlrule);
$urlarr = $ant->getFilteredURL($template);
/*
echo "</br>key:".$keyword."</br>";
echo "</br>rsize:".$resultSize."</br>";
echo "</br>urlpre:".$urlPre."</br>";
echo "</br>urlrule:".$urlrule."</br>";
echo "</br>templa:".$template."</br>";
*/
//var_dump($urlarr);
echo serialize($urlarr);

When an HTTP server cannot determine the Content-Length: in advance, for instance when the output is produced by a dynamic script as opposed to a static file, it will send the output in chunks (as indicated by the Transfer-Encoding: chunked header). Each chunk is prefixed by length expressed in hexadecimal digits. Those are the "strange strings" that you see. The exact details can be found in:
RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

Related

PHP Extract binary data from header

I am working on my PHP to extract the binary data that I stored the email header in the mysql database. I need some help with extract the binary data to get the attachment binary data.
Example:
UEsDBBQAAAAIAEpZrEjPyoXURw....etc
I don't know how do you extract the binary data if you are looking for a filename, example: email_example1.zip.
Here is the header:
Return-Path: <sender#domain.com>
Delivered-To: chris#domain.com
Received: from domain.com
------=_Part_4094373_1508330616.1564422111167
Content-Type: application/zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="email_example1.zip"
Content-ID: <05063d19-5033-af14-87e2-d2fbf22d5857#yahoo.com>
UEsDBBQAAAAIAEpZrEjPyoXURw....etc
------=_Part_4094373_1508330616.1564422111167
Content-Type: application/zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="example2.zip"
Content-ID: <3b2c4fee-2b28-778b-b27f-c63881d64e17#domain.com>
UEsDBBQAAAAIALtk6U5W+XzU7iM....etc
Here is the PHP:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
//Connect to the database
include('config.php');
$id = $_GET['id'];
$attid = $_GET['attid'];
$message_id = $_GET['msgid'];
$mailbox_sql = 'SELECT * FROM ' . $mailfolder . ' WHERE email_id = ? AND message_id = ?';
$mailbox = $link->prepare($mailbox_sql);
$mailbox->execute([$id,$message_id]);
// set the resulting array to associative
$row = $mailbox->fetch(PDO::FETCH_ASSOC);
if (is_array($row)) {
$attached = $row['attached_files'];
$attached_arr = explode("\n", $attached);
}
foreach ($attached_arr as $files) {
$attached_file = 'attid: ' . $attid . ' filename:';
$attached = '';
if (strpos($files, ' attid: ') !== false) {
$filename = trim(strrchr($files, ':'), ': ');
$files = 'attid: ' . $attid . ' filename: ' . $filename;
}
if (strpos($files, $attached_file) !== false) {
$attached = trim(strrchr($files, ':'), ': ');
}
mailbox = null;
?>
Do you know how I can search the filename in the email header to extract the binary data?
Any advice would be much appreicated.
You need get the input stream directly from the body because your content is application/zip Content-Type: application/zip .
To do that u can use php://input :
$input = file_get_contents('php://input');
$binary = base64ToBinary($input);
function base64ToBinary(string $string): string {
if (strpos($string, ';base64,') !== false) {
$string = explode(';base64,', $string)[1];
}
return base64_decode($string);
}
The file name is exposed via Content-Disposition Header:
In your post you have Content-Disposition: attachment; filename="email_example1.zip" you can just parse it from there.
EDIT
How to parse your file name from Header:
$value = $_SERVER['HTTP_CONTENT_DISPOSITION'];
$filename = 'default_name.zip';
if (preg_match('/filename="-(.*?)-"/', $value, $match) == 1) {
$filename = $match[1];
}
The code I provided works 100% for the Content Disposition Header you provided:
If it doesn't work for you that means the format you posted is wrong and check this Question for an answer on how to get file name from content disposition header .
Otherwise your request has nothing to do about Binary data it's parsing about parsing value from string. Please update your question description to match what you want to achieve.

Yii2 setDownloadHeaders() is not working

Code
public function actionExport() {
ini_set('memory_limit','32M');
$whileAgo = date('Y-m-d', time() - 2*24*60*60); // 7-9 seems to be the limit for # days before the 30s timeout
$agkn = AdGroupKeywordNetwork::find()
->select(['field1', 'field2', ...])
->where(['>', 'event_date', $whileAgo])->asArray()->each(10000);
$dateStamp = date('Y-m-d');
Yii::$app->response->setDownloadHeaders("stats_$dateStamp.csv", 'text/csv');
echo 'id,ad_group_keyword_id,keyword,network_id,quality,event_date,clicks,cost,impressions,position,ebay_revenue,prosperent_revenue'.PHP_EOL;
// flush(); // gives us 55s more // doesn't work with gzip
foreach ($agkn as $row) {
echo join(',', $row).PHP_EOL;
// flush();
}
}
Tested:
$ time (curl -sv -b 'PHPSESSID=ckg8l603vpls8jgj6h49d32tq0' http://localhost:81/web/ad-group-keyword-network/export | head)
...
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
<
{ [8277 bytes data]
id,ad_group_keyword_id,keyword,network_id,quality,event_date,clicks,cost,impressions,position,ebay_revenue,prosperent_revenue
9690697,527322,ray ban predator,1,6,2015-11-22,0,0.00,1,5.0,,
It's not downloading a CSV file in the browser either. It's not setting the headers. What is wrong?
Reference: http://www.yiiframework.com/doc-2.0/yii-web-response.html#setDownloadHeaders()-detail
It's because php send header at first echo, before Yii does it.
There are some way to solve the issue.
Collect output to buffer, then send it.
Yii::$app->response->setDownloadHeaders("stats_$dateStamp.csv", 'text/csv');
$data = 'id,ad_group_keyword_id,keyword,network_id,quality,event_date,clicks,cost,impressions,position,ebay_revenue,prosperent_revenue'.PHP_EOL;
foreach ($agkn as $row) {
$data .= join(',', $row).PHP_EOL;
}
return $data;
If output is too large to fit in memory, then data may be stored to temp file. Then send file and delete temp file. There is no need to set header manually in this case.
$filePath = tempnam(sys_get_temp_dir(), 'export');
$fp = fopen($filePath, 'w');
if ($fp) {
fputs($fp, ...);
}
fclose($fp);
return Yii::$app->response->sendFile($filePath, "stats_$dateStamp.csv")
->on(\yii\web\Response::EVENT_AFTER_SEND, function($event) {
unlink($event->data);
}, $filePath);

How to easily decode HTTP-chunked encoded string when making raw HTTP request?

I want to make HTTP request without having dependency to cURL and allow_url_fopen = 1 by opening socket connection and send raw HTTP request:
/**
* Make HTTP GET request
*
* #param string the URL
* #param int will be filled with HTTP response status code
* #param string will be filled with HTTP response header
* #return string HTTP response body
*/
function http_get_request($url, &$http_code = '', &$res_head = '')
{
$scheme = $host = $user = $pass = $query = $fragment = '';
$path = '/';
$port = substr($url, 0, 5) == 'https' ? 443 : 80;
extract(parse_url($url));
$path .= ($query ? "?$query" : '').($fragment ? "#$fragment" : '');
$head = "GET $path HTTP/1.1\r\n"
. "Host: $host\r\n"
. "Authorization: Basic ".base64_encode("$user:$pass")."\r\n"
. "Connection: close\r\n\r\n";
$fp = fsockopen($scheme == 'https' ? "ssl://$host" : $host, $port) or
die('Cannot connect!');
fputs($fp, $head);
while(!feof($fp)) {
$res .= fgets($fp, 4096);
}
fclose($fp);
list($res_head, $res_body) = explode("\r\n\r\n", $res, 2);
list(, $http_code, ) = explode(' ', $res_head, 3);
return $res_body;
}
The function works ok, but since I'm using HTTP/1.1, the response body usually returned in Chunked-encoded string. For example (from Wikipedia):
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
I don't want to use http_chunked_decode() since it has PECL dependency and I want a highly portable code.
How to easily decode HTTP-chunked encoded string so my function can return the original HTML? I also have to make sure that the length of the decoded string match with the Content-Length: header.
Any help would be appreciated. Thanks.
Since the function returns the HTTP response header, you should check if 'Transfer-Encoding' is 'chunked' then decode the chunked-encoded string.
In pseudocode:
CALL parse_http_header
IF 'Transfer-Encoding' IS 'chunked'
CALL decode_chunked
Parsing HTTP response header:
Below is the function to parse HTTP response header to associative array.
function parse_http_header($str)
{
$lines = explode("\r\n", $str);
$head = array(array_shift($lines));
foreach ($lines as $line) {
list($key, $val) = explode(':', $line, 2);
if ($key == 'Set-Cookie') {
$head['Set-Cookie'][] = trim($val);
} else {
$head[$key] = trim($val);
}
}
return $head;
}
The function will return an array like this:
Array
(
[0] => HTTP/1.1 200 OK
[Expires] => Tue, 31 Mar 1981 05:00:00 GMT
[Content-Type] => text/html; charset=utf-8
[Transfer-Encoding] => chunked
[Set-Cookie] => Array
(
[0] => k=10.34; path=/; expires=Sat, 09-Jun-12 01:58:23 GMT; domain=.example.com
[1] => guest_id=v1%3A13; domain=.example.com; path=/; expires=Mon, 02-Jun-2014 13:58:23 GMT
)
[Content-Length] => 43560
)
Notice how the Set-Cookie headers parsed to array. You need to parse the cookies later to associate a URL with the cookies need to be sent.
Decode the chunked-encoded string
The function below take the chunked-encoded string as the argument, and return
the decoded string.
function decode_chunked($str) {
for ($res = ''; !empty($str); $str = trim($str)) {
$pos = strpos($str, "\r\n");
$len = hexdec(substr($str, 0, $pos));
$res.= substr($str, $pos + 2, $len);
$str = substr($str, $pos + 2 + $len);
}
return $res;
}
// Given the string in the question, the function above will returns:
//
// This is the data in the first chunk
// and this is the second one
// consequence
I don't know if it's optimal for you what you need to do but, if you specify HTTP/1.0 instead of HTTP/1.1, you will not get a chunked response.
this Function use in Wordpress.
function decode_chunked($data) {
if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
return $data;
}
$decoded = '';
$encoded = $data;
while (true) {
$is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
if (!$is_chunked) {
// Looks like it's not chunked after all
return $data;
}
$length = hexdec(trim($matches[1]));
if ($length === 0) {
// Ignore trailer headers
return $decoded;
}
$chunk_length = strlen($matches[0]);
$decoded .= substr($encoded, $chunk_length, $length);
$encoded = substr($encoded, $chunk_length + $length + 2);
if (trim($encoded) === '0' || empty($encoded)) {
return $decoded;
}
}
// We'll never actually get down here
// #codeCoverageIgnoreStart
}

HTTP Response-> Getting an exact number of bytes, then closing the connection

I am running into a silly problem: I need to get a certain number of bytes, then close the connection. I've found I can extract the "Content Length" from the header, and use the length to determine just how many more bytes I should get before severing the connection. However, it appears I have made a mistake. It is only getting 40 bytes, instead of 2428 (as it should). Perhaps I am not using fgets() correctly?
Here is the code:
private static function Send($URL, $Data) {
$server = parse_url($URL, PHP_URL_HOST);
$port = parse_url($URL, PHP_URL_PORT);
// If the parsing the port information fails, we will assume it's on a default port.
// As such, we'll set the port in the switch below.
if($port == null) {
switch(parse_url($URL, PHP_URL_SCHEME)) {
case "HTTP":
$port = 80;
break;
case "HTTPS":
$port = 443;
break;
}
}
// Check if we are using a proxy (debug configuration typically).
if(\HTTP\HTTPRequests::ProxyEnabled) {
$server = \HTTP\HTTPRequests::ProxyServer;
$port = \HTTP\HTTPRequests::ProxyPort;
}
// Open a connection to the server.
$connection = fsockopen($server, $port, $errno, $errstr);
if (!$connection) {
die("OMG Ponies!");
}
echo "===========================================================<BR>";
echo "Connection Open<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
echo "Sending Request<BR>";
fwrite($connection, $Data);
echo "Request Sent.";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
$responseheader = "";
$responsebody = "";
/*
\HTTP\HTTPRequests::$start = NULL;
\HTTP\HTTPRequests::$timeout = 10;
// #todo: Rewrite this. Should keep checking for '/r/n/r/n', then check for a content length header. If found, keep grabbing bytes, then close. If not, then close immediately.
while(!\HTTP\HTTPRequests::safe_feof($connection, \HTTP\HTTPRequests::$start) && (microtime(true) - \HTTP\HTTPRequests::$start) < \HTTP\HTTPRequests::$timeout)
{
$response .= fgets($connection);
}
*/
echo "Getting Response<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
while(!feof($connection) && !(strlen(strstr($responseheader,"\r\n\r\n"))>0)) {
$responseheader .= fgets($connection);
}
echo "The Header is fully received at " . date("H:i:su", time()) . "<BR>";
echo "Header (raw):" . "<BR>";
echo "/////////////////////////////////////////////<BR>";
echo $responseheader . "<BR>";
echo "/////////////////////////////////////////////<BR>";
if((strlen(strstr($responseheader,"Content-Length:"))>0)) {
$contentlength = ((int)(\Extract\Extract::GetContentLength($responseheader)));
//for($i = 0; $i < $contentlength; $i++) {
$responsebody .= fgets($connection, $contentlength);
//}
echo "The Body is fully received at " . date("H:i:su", time()) . "<BR>";
echo "Body (raw):" . "<BR>";
echo "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}<BR>";
echo $responsebody . "<BR>";
echo "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}<BR>";
echo "<B>!Content length is " . strlen($responsebody) . ". It should be " . $contentlength . "!</B><BR>";
}
echo "Response Received.<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
fclose($connection);
echo "Connection Closed.<BR>";
echo "The Time is " . date("H:i:su", time()) . "<BR>";
echo "Exiting Send() method.<BR>";
echo "===========================================================<BR>";
echo "<BR>";
return $responseheader . $responsebody;
}
And here is the output:
===========================================================
Connection Open
The Time is 15:57:29000000
Sending Request
Request Sent.The Time is 15:57:29000000
Getting Response
The Time is 15:57:29000000
The Header is fully received at 15:57:29000000
Header (raw):
/////////////////////////////////////////////
HTTP/1.1 207 Multi-Status Date: Wed, 11 Apr 2012 19:57:18 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.14 with Suhosin-Patch mod_ssl/2.2.8 OpenSSL/0.9.8g mod_wsgi/2.0 Python/2.5.2 mod_perl/2.0.3 Perl/v5.8.8 X-Powered-By: PHP/5.2.4-2ubuntu5.14 DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule Content-Location: /davical/caldav.php/rwr26/home/ ETag: "8378ead7e628deafd91ec99dc180ad74" X-DAViCal-Version: DAViCal/0.9.9; DB/1.2.9 Content-Length: 2428 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/xml; charset="utf-8"
/////////////////////////////////////////////
The Body is fully received at 15:57:29000000
Body (raw):
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
!Content length is 40. It should be 2428!
Response Received.
The Time is 15:57:29000000
Connection Closed.
The Time is 15:57:29000000
Exiting Send() method.
===========================================================
Why am I doing it this way? Apparently, I was running into some sort of a timeout error, which makes each connection stay open for 30 seconds (yes, 30 whole seconds). So I wrote this code to get the exact number of bytes, then close. Any help is greatly appreciated.
I changed the content line "$responsebody .= fgets($connection, $contentlength);" to "$responsebody .= stream_get_line($connection, $contentlength);". Thing is wicked fast now, and works.

Using PHP to read a web page with fsockopen(), but fgets is not working

Im using this code here: http://www.digiways.com/articles/php/httpredirects/
public function ReadHttpFile($strUrl, $iHttpRedirectMaxRecursiveCalls = 5)
{
// parsing the url getting web server name/IP, path and port.
$url = parse_url($strUrl);
// setting path to '/' if not present in $strUrl
if (isset($url['path']) === false)
$url['path'] = '/';
// setting port to default HTTP server port 80
if (isset($url['port']) === false)
$url['port'] = 80;
// connecting to the server]
// reseting class data
$this->success = false;
unset($this->strFile);
unset($this->aHeaderLines);
$this->strLocation = $strUrl;
$fp = fsockopen ($url['host'], $url['port'], $errno, $errstr, 30);
// Return if the socket was not open $this->success is set to false.
if (!$fp)
return;
$header = 'GET / HTTP/1.1\r\n';
$header .= 'Host: '.$url['host'].$url['path'];
if (isset($url['query']))
$header .= '?'.$url['query'];
$header .= '\r\n';
$header .= 'Connection: Close\r\n\r\n';
// sending the request to the server
echo "Header is: <br />".str_replace('\n', '\n<br />', $header)."<br />";
$length = strlen($header);
if($length != fwrite($fp, $header, $length))
{
echo 'error writing to header, exiting<br />';
return;
}
// $bHeader is set to true while we receive the HTTP header
// and after the empty line (end of HTTP header) it's set to false.
$bHeader = true;
// continuing untill there's no more text to read from the socket
while (!feof($fp))
{
echo "in loop";
// reading a line of text from the socket
// not more than 8192 symbols.
$good = $strLine = fgets($fp, 128);
if(!$good)
{
echo 'bad';
return;
}
// removing trailing \n and \r characters.
$strLine = ereg_replace('[\r\n]', '', $strLine);
if ($bHeader == false)
$this->strFile .= $strLine.'\n';
else
$this->aHeaderLines[] = trim($strLine);
if (strlen($strLine) == 0)
$bHeader = false;
echo "read: $strLine<br />";
return;
}
echo "<br />after loop<br />";
fclose ($fp);
}
This is all I get:
Header is:
GET / HTTP/1.1\r\n
Host: www.google.com/\r\n
Connection: Close\r\n\r\n
in loopbad
So it fails the fgets($fp, 128);
Is there a reason you aren't using PHP's built-in, enabled-by-default ability to fetch remote files using fopen?
$remote_page = file_get_contents('http://www.google.com/'); // <- Works!
There are also plenty of high-quality third-party libraries, if you need to do something like fetch headers without thinking too hard. Try Zend_Http_Client on for size.
The flaw is here:
$good = $strLine = fgets($fp, 128);
if(!$good)
{
echo 'bad';
return;
}
fgets() returns either a string on success, or FALSE on failure. However, if there was no more data to be returned, fgets() will return the empty string (''). So, both $good and $strLine are set to the empty string, which PHP will happily cast to FALSE in the if() test. You should rewrite as follows:
$strLine = fgets($fp, 128);
if ($strLine === FALSE) { // strict comparison - types and values must match
echo 'bad';
return;
}
There's no need for the double assignment, as you can test $strLine directly.

Categories