Tag: «php»
A Note on PHP Sessions and the Garbage Collector
I ran into an unpleasant issue on one of the work servers here.
Historically, when the site's PHP engine starts up, this value gets set:
session_save_path( PATH_TMP );
ini_set( 'session.gc_maxlifetime', 1800 );
In other words, we have a custom directory for storing sessions, and its lifetime is set to half an hour for the garbage collector.
The server uses php-fpm. I noticed problems in the logs - as if the disk had run out of space. Even though there was still plenty of it. My first thought was that somewhere a huge number of tiny files had been created. As it turned out, session files in our custom directory were not being deleted. I started digging and found the session.gc_probability parameter on php.net, which in php.ini is supposed to be set to 1 - this is the probability that the garbage collector will also run when a script executes.
In the user notes there is a note that Debian sets this parameter to 0. Googling says this is related to the permissions on the default folder /var/lib/php5, which do not allow PHP's garbage collection to clean up old files there. So Debian disables PHP's garbage collector and apparently runs some cron job of its own as root for cleanup. It seems to look for files in the standard directory, and since that does not match our PATH_TMP directory, the sessions were not being removed.
That's how it goes. The options are either to set up your own cron job for cleanup, for example:
0,30 * * * * find /path/to/tmp -mmin +30 -exec rm {} \;
Or specify the default folder in php.ini. But, for example, if a site has 2 projects that use different temporary folders for storing sessions, then you will have to configure something for both of them.
Or add this line when the script starts: ini_set('session.gc_probability', 1);
Personally, I like having my own cron job more. Although maybe adding one more line to the script is better, since it could save you from this problem in the future. Still, cron somehow feels more reliable. Now I just have to figure out how to delete the files that have piled up over 6 months. Midnight Commander spent about 2 hours scanning the folder. When the counter went past 49 million, I gave up on the scan, started deletion, and went to sleep.
That's that.
Detecting Photo Orientation in PHP via EXIF
Cheat sheet.
Vertical photos shot in portrait mode on Android and iPhone are saved as horizontal images, but the photo orientation is written into EXIF.
If you output the value of this command:
$exif = exif_read_data( $existingFilePath, 0, true);
Then among the array values you will see:
array
(
...
[IFD0] => Array
(
[Make] => Sony
[Model] => LT25i
[Orientation] => 6
[XResolution] => 72/1
[YResolution] => 72/1
[ResolutionUnit] => 2
[Software] => 9.1.A.1.145_58_f100
[DateTime] => 2013:07:26 17:00:01
[YCbCrPositioning] => 1
[Exif_IFD_Pointer] => 214
[GPS_IFD_Pointer] => 626
)
...
)
In this case it means that when this photo is displayed, the app showing it must rotate the image by 90 degrees because the photo is in portrait orientation.
To avoid problems when uploading images to the server and processing them (creating a reduced copy, creating a thumbnail), you can detect such photos with this code:
<?php
imagecopyresampled( $resultImage, $sourceImage, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
$exif = exif_read_data( $existingFilePath, 0, true);
if( false === empty( $exif['IFD0']['Orientation'] ) ) {
switch( $exif['IFD0']['Orientation'] ) {
case 8:
$resultImage = imagerotate( $resultImage, 90, 0 );
break;
case 3:
$resultImage = imagerotate( $resultImage,180,0);
break;
case 6:
$resultImage = imagerotate( $resultImage,-90,0);
break;
}
}
Interestingly, Windows Phone saves a portrait photo as a vertical image.
FCKEditor and the «Access Denied» error
Updated Nginx and PHP on my server to the latest stable versions. PHP is currently 5.4.6.
After the update FCKEditor stopped working — instead of it I was getting an «Access Denied» message.
FCKEditor is rendered on the page through an iframe, and that’s where the message was hanging. I dug through the editor’s sources thinking maybe there was some PHP version check somewhere, but didn’t find anything special. The iframe loads fckeditor/editor/fckeditor.html. Opening that file directly produced the same error. I started suspecting Nginx, but it turned out to be neither Nginx nor the editor’s code — it was PHP itself (php-fpm).
Googling «Access Denied» wasn’t easy, but glancing into the error logs I spotted the keyword security.limit_extensions. From the name, this php-fpm.conf option controls which file extensions PHP code is allowed to execute in. Starting with PHP 5.3.9, for security reasons, if this option isn’t specified in the config, PHP only runs in .php files (I don’t know what it was before). FCKEditor wires itself up through PHP in some clever/messy way that ends up executing code in that very fckeditor.html file (even though there’s no PHP code inside — just a long framework setup). That’s why php-fpm was returning «Access Denied».
Fix: in php-fpm.conf, or better, in the pool .conf file (something like /etc/php-fpm/pulls/mysite.conf), add this line:
security.limit_extensions = .php .html
That’s the fix. Spent almost an hour and a half tracking it down — without knowing the editor’s code I couldn’t immediately figure out where to dig. So I’ll leave this here. Maybe it’ll save someone else the same trouble.
Trimming the trailing slash in URLs with a 301 redirect
Why not pin this here — easier to find later, when I need it again. Search engines often treat pages like
arm1.ru/blog/yandex-upal-panika-v-twitter
and
arm1.ru/blog/yandex-upal-panika-v-twitter/
as different pages. So you end up with the same content technically living at two URLs, which isn’t great. Below the cut — code that automatically strips a trailing / via a 301 redirect, so search engines don’t end up with duplicate pages.
<?php
# strip the QUERY_STRING from REQUEST_URI
$uri = $_SERVER['REQUEST_URI'];
if ( false === empty( $_SERVER['QUERY_STRING'] ) )
$uri = str_replace( '?' . $_SERVER['QUERY_STRING'], '', $uri );
# 301 redirect when there is a trailing slash on $uri
if ( substr( $uri, -1 ) == '/' && strlen( $uri ) > 1 ) {
$queryString = '';
if ( false === empty( $_SERVER['QUERY_STRING'] ) )
$queryString = '?' . $_SERVER['QUERY_STRING'];
header( 'Location: ' . substr( $uri, 0, -1 ) . $queryString, true, 301 );
exit;
}
Posting to Twitter via PHP
Long meant to share my modest set of functions for posting tweets to Twitter. Maybe useful to someone — none of it came to me right away, especially the signature generation. Plus this is my attempt to lock into my head what I’ve learnt and coded. The best way to do that, I think, is to try to explain it to someone else :) Description and code below the cut.
Resizing animated GIF images with Imagick
At work I ran into the need to process animated GIF avatars. The source images can be of any size, and they need to be downsized to a target size with cropping to a square. Below the cut — how we solved it.
Simple online TimeStamp converter
At work I occasionally have to look at some data from the database. Times we mostly store as TimeStamp (the number of seconds since the dawn of the Unix world — 1 January 1970).
A number like 1305233826 tells you nothing about what date it is. Writing the conversion in some script every time gets tedious, so I made an online converter. It shows the time in a human-readable form.
Enjoy. Online TimeStamp Converter