htscanner: Enabling php_admin directives in .htaccess under php-fastcgi (Plesk 9.x + CentOS 5)

[update 201107061858]
For per-domain php.ini under php-fastcgi see here
[/update]

Under Plesk running php-fastcgi  it is not possible to use php_admin_flag and php_admin_value directives in .htaccess files on a per-directory basis. Luckily this can be easily enabled with the htscanner extension.

All the information to get this working is out there, but as per usual, you have to piece it together from a variety of sources to get a complete picture. Here I shall provide a single complete set of instructions that have been proven to work on a CentOS5 box with Plesk 9 – although Plesk should be an irrelevance here, I mention it for completeness.

I am using PuTTY as my SSH client.

In order to install and use htscanner v1.0,0 , you must have the following things (aka dependancies):

PHP Version: PHP 5.1.0 or newer
PEAR Package: PEAR Installer 1.4.8 or newer

Odds of having >=PHP 5.1 without PEAR are slim to my knowledge, and installing it is beyond the scope of this post.

Got those? Ready to go!

To provide absolute clarity for inexperience bods, # is the SSH command prompt and shouldn’t be included in typed commands! And if you REALLY need your hand held, hit [enter] after each line. Just so you don’t sit there wondering why nothing is happening…

Download and extract htscanner

  1. SSH to your server with root access.
  2. Download the latest version of htaccess from http://pecl.php.net/package/htscanner currently 1.0.0
    #  wget http://pecl.php.net/get/htscanner-1.0.0.tgz
  3. Untar the file:
    # tar -xvsf htscanner-1.0.0.tgz

Compile and run installation

  1. Change to the newly created directory:
    # cd htscanner-1.0.0
  2. Run phpize:
    # phpize
  3. Run the configuration script with –enable-htscanner switch
    # ./configure --enable-htscanner
  4. Run make to build the installer:
    # make
  5. Run make install to actually install the extension
    # make install

Add htscanner settings

Either:

For systems that support it, you can simply copy htscanner.ini to your php conf.d directory. This is probably somwhere along the lines of /etc/php.d on CentOS 5 or perhaps for others /etc/httpd/conf.d but if you are having trouble finding it, run
# locate conf.d
You will find a bunch of them though, so make sure it’s the right one. You can also try simply googling your *nix distribution name and conf.d – for example “centos 5 conf.d”

Or:

If you are running SuSE or another flavour of Linux which doesn’t support this, you can add the contents of htscanner.ini to your php.ini file. To locate yours try the tips above for finding the php conf.d directory
The htscanner.ini file currently looks like this:
[htscanner]extension="htscanner.so"; The configuration file htscanner needs to scan for php_* directivesconfig_file=".htaccess"; The fallback docroot when htscanner can't determine the current docrootdefault_docroot="/"default_ttl=300; Stop when an error occured in RINIT (no document root, cannot get path_translated,...)stop_on_error = 0; Warn when an option cannot be setverbose = 0

You should check the contents of your htscanner.ini file though, to be safe.
This is simple enough, but for the sake of completeness and for any poor n00bs out there, to do this, and then add to php.ini using ‘vi’ text editor: 

  1. Open htscanner.ini:
    # vi docs/htscanner.ini
  2. Highlight all text to copy to the clipboard
  3. Exit vi by simply typing
    :q
    and hitting [Enter]
  4. Open php.ini:
    # vi /etc/php.ini
  5. Scroll to the bottom of the file with [pgdn] key
  6. Enter editing mode by hitting [i] key
  7. Press [->] Left arrow key to ensure you are at the end of the last line
  8. Hit [Enter] to start a new line
  9. Right-click the mouse to paste the htscanner.ini contents
  10. Exit editing mode by hitting [Esc] key
  11. Save and quit vi:
    :wq 
    and hit [Enter] 

Restart Apache

On CentOS 5 and similar distros:
#  service httpd restart
For other *nix versions, y’know, google it. Why not, sounds like fun to me?

And voila. You should now be up and running with per directory php_admin directives in your .htaccess files.

Integrating the Zencoder API

I have been working on integrating the Zencoder API with my CMS.

Where you have a configuration file that users can, of course, completely mangle, you need to do a lot of error checking to ensure that things are correctly set and keep the users informed.

Most of the things you will wanting to be checking are pretty straightforward, but one of the slightly more complex ones is the protocol for returning the encoded files.
Zencoder supports ftp, sftp and ftps, as well as Cloud File and Amazon S3.
Regex for testing protocols is widely available online, but we are looking at slightly less usual options than http(s) vs ftp.

Protocol:

First we need to allow for all 3 flavours of ftp
/^(s?(ftp)s?):///

Cloud file uses their cf:// protocol, or alternatively cf+xx:// where xx is the two letter country code of the location – currently Cloud File supports us and uk, defaulting to us if not specified. However, realistically, Cloud File may support more countries in future, so we need to allow for them.
/^((cf)(+[a-z]{2})?):/// 

Amzon S3 uses their s3:// protocol.
/^(s3):///i';

Sticking all three together we get:
/^(s?(ftp)s?|((cf)(+[a-z]{2})?)|s3):///'

To put it into action:
$host = 'ftps://mydomain.com';$zencoder_protocol_regex = '/^(s?(ftp)s?|((cf)(+[a-z]{2})?)|s3):///i';if(strpos($host, '://') > 0){ preg_match($zencoder_protocol_regex, $host, $result); if(count($result) == 0){ //Incorrect protocol }else{ if($result[0] = 'ftp://'){ //Protocol is ftp - give security warning } $protocol = $result[0]; $host = str_replace($result[0], '' , $host); }}else{ $protocol = 'ftps://';}

URL with username and password:

The next crucial step is to construct a valid destination url that includes a username and password, while allowing for S3 accounts, which don’t require user/pass. Non alpha-numeric characters need to be percent encoded:
$user = 'username';$pass = 'password';$file = 'filename.ext';if(strlen($user) > 0){ $user = rawurlencode($user) . ':';}if(strlen($pass) > 0){ $pass = rawurlencode($pass) . '@';}$output = $protocol . $user . $pass . $host .  '/' . $file

So if we pass in the following variables:
$host = 'ftps://ftp.mydomain.com';$user = 'bob@mydomain.com';$pass = 'foo!';$file = 'filename.ext';

We will get:
ftps://bob%40mydomain.com:foo%21@ftp.mydomain.com

Some notes on FTP protocols:

FTP: Completely unsecure – username and password sent in plain text
FTPS: User/pass sent over TLS/SSL – data not encrypted
SFTP: All data encrypted over SSH
So why not use SFTP all the time? Well, sometimes it’s just not available if you are on a shared server, and if it is, it’s often not available for additional FTP users as SSH requires shell access. As you don’t want to be giving away your master FTP account details, an additional FTP account (which can point directly at the required folder) is preferable, and unless your videos are highly sensitive or valuable, FTPS should do just fine.

Want to see it all put together?

http://pastebin.com/iB3X1Dq5
This is the production code on my server, so it has a lot of things that are custom to the CMS – it should be pretty straightforward to follow though. You will also need to trawl it for the variables that need to be passed to the script, but you should be reading the Zencoder docs to familiarise yourself with the requirements anway. Sorry I don’t have time to expand it all currently.
It is configured to output webm, ogg and mp4 files for HTML5 video players.

You will also need the API class from Zencoder – here’s a copy for convenience:
http://pastebin.com/eVbF879j
I haven’t yet integrated thumbnails, or processing a Zencoder notification returned to a script