Categories
PHP Server Software

PHP Profiling Time and Memory with OSX 10.10 and Xdebug

First you need to have installed Xdebug, to install Xdebug on Linux debian click here.

Configure XDEBUG for time specific profiling:

[code lang=”bash”]
mkdir /var/log/xdebug-profiling-output/
chmod -R 777 /var/log/xdebug-profiling-output/
nano /etc/php5/apache2/conf.d/xdebug.ini

xdebug.profiler_output_dir=/var/log/xdebug-profiling-output/
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1
[/code]

These settings mean that time profiling outputs will be stored in /var/log/xdebug-profiling-output/, profiling will be disabled by default and only activated using trigger. Having profiling on as default is not recommended because it drains the system resources.

Now reboot Apache2:

[code lang=”bash”]
/etc/init.d/apache2 graceful
[/code]

To generate a profiling log, append ?XDEBUG_PROFILE=1 to your site-url, like this: http://www.mywebsite.com/index.php?XDEBUG_PROFILE=1

To be able to parse the output in OSX 10.10 you need Graphviz installed, install it using Homebrew by running:

[code lang=”bash”]
brew install qcachegrind
[/code]

Generate a log on your website and then remember the filename path. Copy it over to your OSX machine using:

[code lang=”bash”]
scp root@mywebsite.com:/var/log/xdebug-output/cachegrind.out.4852 ~/Downloads/
[/code]

Now open this file in the application qcachegrind to analyze the profiling. You can also analyze the Xdebug profiling output using Php Storms built-in Xdebug Profiler Snapshot analyzer if you have it.

Configure XDEBUG for memory specific profiling:

[code lang=”bash”]
mkdir /var/log/xdebug-trace-output/
chmod -R 777 /var/log/xdebug-trace-output/
nano /etc/php5/apache2/conf.d/xdebug.ini

xdebug.auto_trace=0
xdebug.trace_enable_trigger=1
xdebug.trace_output_dir=/var/log/xdebug-trace-output/
xdebug.collect_params=0
xdebug.trace_format=1
xdebug.show_mem_delta=1
xdebug.collect_assignments=1
[/code]

These settings means that memory profiling will be disabled by default to save resources, profiling logs will be generated in the folder /var/log/xdebug-trace-output/.

Now reboot Apache2

[code lang=”bash”]
/etc/init.d/apache2 graceful
[/code]

To generate a profiling log, append ?XDEBUG_TRACE=1 to your site-url, like this: http://www.mywebsite.com/index.php?XDEBUG_TRACE=1

Check generate filename and copy trace log from remote host to OSX.

[code lang=”bash”]
scp root@mywebsite.com:/var/log/xdebug-trace-output/trace.2043925204.xt ~/Downloads/
[/code]

Now you can open the log in text-editor.

Categories
PHP Programming

PHP serializing and unserializing with circular references

In Aomebo Framework, which is my PHP MVC framework. Runtimes can be serialized and unserialized to improve speed.

Runtimes could contain a list of Routes, which is used for URL routing and URL generation. The Routes contain a reference to the Runtime that they are associated with.

So we have the following relationships.

Runtime -> Routes, Route -> Runtime = Runtime <-> Route

In order to improve the speed of the framework I was implementing a serializing and unserializing feature. Serializing Runtimes without Routes worked from scratch. When a Runtime contain at least one Route, the php execution stopped without any notice (Fatal Error). Was hard to debug.

I solved it by doing the following.

Serializing:
1. Runtime Routes are stored outside of Runtimes.
2. Serialize all Runtimes without their Routes.
3. Replace the references to Runtimes in Routes with class-name strings only.
4. Serialize all Routes.

Unserializing:
1. Unserialize all Runtimes (no Routes were stored in Runtimes).
2. Unserialize all Routes, references are only class-name strings now.
3. Iterate through Routes and replace reference class-name strings with instanciated Runtimes based on class-name.

Now it works as expected, and with high improve in speed and resources.

Categories
Imagick PHP Programming

Get DPI from JPG/JPEG and PNG images with PHP and Imagick

Add these functions to a class, then just call $class::getImageDpi($filename) to get the DPI returned. DPI is searched both in the image header-data and the EXIF data. Use these functions according to MIT license.

[code lang=”php”]

/**
* @param string $filename
* @return array
* @throws Exception
*/
public static function getImageDpi($filename)
{
if (!empty($filename)
&& file_exists($filename)
) {

$fileMime = self::getFileMimeType($filename);

if ($fileMime == ‘image/jpeg; charset=binary’
|| $fileMime == ‘image/jpg; charset=binary’
|| $fileMime == ‘image/jpeg2; charset=binary’
) {
return self::getImageJpgDpi($filename);
} else if ($fileMime == ‘image/png; charset=binary’) {
return self::getImagePngDpi($filename);
} else {
return array(
‘x’ => 72,
‘y’ => 72,
);
}

} else {
Throw new \Exception(‘Invalid parameters’);
}
}

/**
* Uses unix command file -bi for determining file typ.
*
* jpeg = image/jpeg; charset=binary
* gif = image/gif; charset=binary
* pdf = application/pdf; charset=binary
*
* @static
* @param string $absolutePath
* @throws Exception
* @return string|bool
*/
public static function getFileMimeType($absolutePath)
{
if (!empty($absolutePath)) {
if (file_exists($absolutePath)) {
if ($return = exec(
‘file -bi — ‘ . escapeshellarg($absolutePath))
) {
return $return;
}
}
} else {
Throw new Exception(
‘Invalid parameters for ‘ . __FUNCTION__
. ‘ in ‘ . __FILE__);
}
return false;
}

/**
* @param string $filename
* @return array
* @throws Exception
*/
public static function getImageJpgDpi($filename)
{
if (!empty($filename)
&& file_exists($filename)
) {

$dpi = 0;
$fp = @fopen($filename, ‘rb’);

if ($fp) {
if (fseek($fp, 6) == 0)
{
if (($bytes = fread($fp, 16)) !== false)
{
if (substr($bytes, 0, 4) == “JFIF”)
{
$JFIF_density_unit = ord($bytes[7]);
$JFIF_X_density = ord($bytes[8])*256 + ord($bytes[9]);
$JFIF_Y_density = ord($bytes[10])*256 + ord($bytes[11]);

if ($JFIF_X_density == $JFIF_Y_density)
{
if ($JFIF_density_unit == 1) {
$dpi = $JFIF_X_density;
} else if ($JFIF_density_unit == 2) {
$dpi = $JFIF_X_density * 2.54;
}
}
}
}
}
fclose($fp);
}

if (empty($dpi)) {
if ($exifDpi = self::getImageDpiFromExif($filename)) {
$dpi = $exifDpi;
}
}

if (!empty($dpi)) {
return array(
‘x’ => $dpi,
‘y’ => $dpi,
);
} else {
return array(
‘x’ => 72,
‘y’ => 72,
);
}

} else {
Throw new \Exception(‘Invalid parameters’);
}
}

/**
* @static
* @param string $filename
* @return array
* @throws Exception
*/
public static function getImagePngDpi($filename)
{
if (!empty($filename)
&& file_exists($filename)
) {

$fh = fopen($filename, ‘rb’);

if (!$fh) {
return false;
}

$buf = array();

$x = 0;
$y = 0;
$units = 0;

while(!feof($fh))
{
array_push($buf, ord(fread($fh, 1)));
if (count($buf) > 13)
array_shift($buf);
if (count($buf) < 13) continue; if ($buf[0] == ord('p') && $buf[1] == ord('H') && $buf[2] == ord('Y') && $buf[3] == ord('s')) { $x = ($buf[4] << 24) + ($buf[5] << 16) + ($buf[6] << 8) + $buf[7]; $y = ($buf[8] << 24) + ($buf[9] << 16) + ($buf[10] << 8) + $buf[11]; $units = $buf[12]; break; } } fclose($fh); if ($x != false && $units == 1 ) { $x = round($x * 0.0254); } if ($y != false && $units == 1 ) { $y = round($y * 0.0254); } if (empty($x) && empty($y) ) { if ($exifDpi = self::getImageDpiFromExif($filename)) { $x = $exifDpi; $y = $exifDpi; } } if (!empty($x) || !empty($y) ) { return array( 'x' => $x,
‘y’ => $y,
);
} else {
return array(
‘x’ => 72,
‘y’ => 72,
);
}

} else {
Throw new \Exception(‘Invalid parameters’);
}
}

/**
* Read EXIF data.
*
* @static
* @param string $filename
* @throws \Exception
* @return bool|float
*/
public static function getImageDpiFromExif($filename)
{

if (!empty($filename)
&& file_exists($filename)
) {
if (function_exists(‘exif_read_data’)) {
if ($exifData = exif_read_data($filename)) {
if (isset($exifData[‘XResolution’])) {
if (strpos($exifData[‘XResolution’], ‘/’) !== false) {
if ($explode = explode(‘/’, $exifData[‘XResolution’])) {
return (float) ((int) $explode[0] / (int) $explode[1]);
}
} else {
return (int) $exifData[‘XResolution’];
}
} else if (isset($exifData[‘YResolution’])) {
if (strpos($exifData[‘YResolution’], ‘/’) !== false) {
if ($explode = explode(‘/’, $exifData[‘YResolution’])) {
return (float) ((int) $explode[0] / (int) $explode[1]);
}
} else {
return (int) $exifData[‘YResolution’];
}
}
}
} else {
Throw new \Exception(‘Incompatible system.’);
}
} else {
Throw new \Exception(‘Invalid parameters.’);
}

return false;

}
[/code]

Categories
Imagick PHP Programming

Convert white in image to transparency with Imagick and PHP

Here is a snippet I made which takes a path to an image and if the image doesn’t have any transparency it replaces all white color with 100% transparency.

[code lang=”php”]
/**
* @static
* @param string $oldPath
* @param string|null [$newPath = null]
* @throws \Exception
* @return bool
*/
public static function createShirtImage($oldPath, $newPath = null)
{
if (isset($oldPath)
&& file_exists($oldPath)
) {

if ($resource = new imagick($oldPath)) {

$whitePixel = new ImagickPixel(‘white’);

// Does image not have any transparency?
if (!$resource->getimagealphachannel()) {

$resource->painttransparentimage(
$whitePixel,
0.0,
5000
);

}

$resource->setimagecolorspace(imagick::COLORSPACE_RGB);
$resource->setimageformat(‘png’);

if (empty($newPath)) {
$newPath = $oldPath;
}

if (file_exists($newPath)) {
unlink($newPath);
}

if ($resource->writeimage($newPath)) {

return true;

}

}

} else {
Throw new Exception(‘Invalid parameters’);
}

return false;

}
[/code]

Categories
PHP Programming

PHP Gogobot integration

Since I couldn’t find any documentation on how to integrate Gogobot in PHP I decided to make a blog post about it.

1. Get Client id and Client Secret from Gogobot.

2. Replace $clientId and $clientSecret below with your credentials.

[code lang=”php”]
$clientId = ‘MY ID’;
$clientSecret = ‘MY SECRET’;

$queryParameters = array();
$queryParameters[‘query’] = $query;
$queryParameters[‘lat’] = $lat;
$queryParameters[‘lng’] = $lng;
$queryParameters[‘https’] = (!empty($https) ? 1 : 0);
$queryParameters[‘client_id’] = $clientId;

ksort($queryParameters);

// Calculate payload
$payload = ”;

foreach ($queryParameters as $key => $value)
{
$payload .= $key;
$payload .= $value;
}

$payload .= $clientSecret;

// Generate signature
$signature = hash_hmac(‘sha256’, $payload, $clientSecret, true);
$signature = base64_encode($signature);

$queryParameters[‘signature’] = $signature;

// Generate HTTP
$http = ‘http://api.gogobot.com/api/v3/search/nearby_search/?’;

$queryParameterIndex = 0;
foreach ($queryParameters as $key => $value)
{
if ($queryParameterIndex > 0) {
$http .= ‘&’;
}
$http .= $key . ‘=’ . rawurlencode($value);
$queryParameterIndex++;
}
[/code]

3. After this just make a cURL request and the integration is ready.