Press "Enter" to skip to content

Category: Net: Techy: PHP

Posts about the PHP programming language

Code Snippets: UTF-8 to UTF-16 revisited and expanded

Yes, I know I posted yesterday about converting from UTF-8 to UTF-16BE/UTF-16LE – but I wasn’t happy with the code to convert to UTF16. It relied on mb_convert_encoding which whilst clear, it did mean that sequences sent could be silently “fixed”, lone high/low surrogate code points would be refused to be output (which I actually needed as they were one thing I was trying to test against!), and I just wanted more “insight” into the whole UTF8 to UTF16 system.

Unicode is NOT UTF-8

One thing to remember (and which caused me a timesink) was that Unicode is NOT UTF-8! Unicode is a collection of characters which are usually represented in UTF-8 byte sequences (but can be represented in UTF-16BE/UTF-16LE and UTF32 and others).

Code Snippets: PHP: Converting to/from UTF-8 to UTF16-BE

I needed to convert some Unicode UTF16-BE strings (as used in Java) to UTF-8 (which is “byte-orientated” and so doesn’t need to worry about endianness) – however, there didn’t seem to many examples online. I’m not going to say these methods are robust, 100% accurate for every use case or even the best way to do it – but just ways to do it.

It’s worth noting that Java uses the escape sequence \uXXXX (where X is a hexadecimal code), and PHP uses the nearly similar escape sequence \u{XXXX} . Both seem to use \xXX for a single character.

ADDED: I’ve improved the UTF-8 to UTF-16 code conversion in a newer post.

PHP SplFileInfo string values

Whilst PHP’s documentation of SplFileInfo isn’t “bad” as such, it can be tricky to remember what string functions (such as getBasename, getExtension, getFilename, getPath, getPathname, getRealPath and __toString) return under which circumstances. Hence this post!

To generate this data, we’re going to start off with a RecursiveDirectoryIterator with an optional callback filter (to enable us to later on, filter the returned values):

<?php 
$directoryIterator=new \RecursiveDirectoryIterator(
            '/var/task', // test directory
            \RecursiveDirectoryIterator::SKIP_DOTS // ignore "dot files"
        );
       
        $filterIterator = new \CallbackFilterIterator(
            new \RecursiveIteratorIterator($directoryIterator), 
            function (\SplFileInfo $file) {
           // add filter conditions here
            return true;
        });
        /** @var \SplFileInfo $fileInfo */
        foreach ($filterIterator as $fileInfo) {
            $objectNames= [
                'fileInfo',
                'directoryIterator',
                'filterIterator'
            ]; // which objects (defined above) are we interested in
          $methods = [
                'getBasename',
                'getExtension',
                'getFilename',
                'getPath',
                'getPathname',
                'getRealPath',
                '__toString'
            ]; // which methods of those objects do we want to get. 
           foreach ($objectNames as $objectName) {
               foreach ($methods as $method) {
                    print $objectName . '->' .
                        $method . ' = ' .
                        call_user_func([$$objectName, $method]) .
                        PHP_EOL;
               }
           }
           die(); // we only want the first one as an example
        }

Give the file /var/task/assets/fonts/montserrat-v14-latin-700.eot and the “start” directory of /var/task , we get the following:

  • fileInfo->getBasename = montserrat-v14-latin-700.eot
  • fileInfo->getExtension = eot
  • fileInfo->getFilename = montserrat-v14-latin-700.eot
  • fileInfo->getPath = /var/task/assets/fonts
  • fileInfo->getPathname = /var/task/assets/fonts/montserrat-v14-latin-700.eot
  • fileInfo->getRealPath = /var/task/assets/fonts/montserrat-v14-latin-700.eot
  • fileInfo->__toString = /var/task/assets/fonts/montserrat-v14-latin-700.eot
  • directoryIterator->getBasename = assets
  • directoryIterator->getExtension =
  • directoryIterator->getFilename = assets
  • directoryIterator->getPath = /var/task
  • directoryIterator->getPathname = /var/task/assets
  • directoryIterator->getRealPath = /var/task/assets
  • directoryIterator->__toString = assets
  • filterIterator->getBasename = montserrat-v14-latin-700.eot
  • filterIterator->getExtension = eot
  • filterIterator->getFilename = montserrat-v14-latin-700.eot
  • filterIterator->getPath = /var/task/assets/fonts
  • filterIterator->getPathname = /var/task/assets/fonts/montserrat-v14-latin-700.eot
  • filterIterator->getRealPath = /var/task/assets/fonts/montserrat-v14-latin-700.eot
  • filterIterator->__toString = montserrat-v14-latin-700.eot

Hope it’s useful to someone!

PHP: Flow of data: WordPress – MagicMembers Plugin

I hope this post comes in handy to any one else which has to support/deal with the MagicMembers plugin for WordPress.

The [user_register\ calls mgm_content_hooks.php “function mgm_shortcode_parse” which then calls mgm_user_register_form which is in mgm_form_functions.

If fetches the main registration fields using:
$register_fields = mgm_get_config(‘default_register_fields’,array());
[fields such as username, email address]
and the custom ones using:
$cf_register_page = mgm_get_class(‘member_custom_fields’)->get_fields_where(array(‘display’=>array(‘on_register’=>true)));
[fields such as subscription_options, password, and all others]

However, it then calls the filter mgm_register_form via the line:
$form_html .= apply_filters(‘mgm_register_form’, $form_html);
which calls, via mgm_user_hooks.php, the function mgm_wp_register_form_additional which is defined in core/hooks/mgm_user_hooks.php .

Using the templates it gets from two other filters (mgm_generate_register_form_template and mgm_register_form_template), it then tries to build the template using the filter mgm_generate_register_form_html. This filter (again defined in core/hooks/mgm_user_hooks.php) calls the function mgm_generate_register_form_html (again defined in mgm_user_hooks.php) and then the mgm_register_form_additional_html filter – which isn’t defined.

So, in short:

shortcode [user_register\ -> function mgm_shortcode_parse -> function mgm_user_register_form -> filter mgm_register_form -> function mgm_user_hooks -> function mgm_wp_register_form_additional -> filter mgm_generate_register_form_html -> function mgm_generate_register_form_html -> filter mgm_register_form_additional_html

New Relic, cPanel, Apache and FastCGI PHP

We tend to operate RedHat Enterprise/CentOS based cPanel web hosting accounts for ourselves and our customers and for security, they are configured running PHP under suPHP via CGI/FastCGI. However, for server monitoring, we wanted to be able to use NewRelic for monitoring the sites on an individual level but without the customers having to add newrelic.appname to each of their applications – and we didn’t want each site to have to have its own php.ini, and under suPHP PHP ignores any php_value settings in the Apache configuration. So what to do?

Install New Relic
Well, first of all install New Relic according to your server architecture, then run “newrelic-install” and select all. Now we move on to the cPanel specific setup.

Getting PHP to notice the NewRelic PHP Module
In WHM (:2087), select “PHP Configuration Editor” and then “Advanced mode”. Search for Core “extension” and change the list from something like:
/usr/lib/php/extensions/no-debug-non-zts-20090626/apc.so, pdo.so, pdo_sqlite.so, sqlite.so, pdo_mysql.so, timezonedb.so, uploadprogress.so
to:
/usr/lib/php/extensions/no-debug-non-zts-20090626/apc.so, pdo.so, pdo_sqlite.so, sqlite.so, pdo_mysql.so, timezonedb.so, uploadprogress.so, newrelic.so

Restart Apache (via either WHM or /scripts/restartsrv_apache on the command line) and check everything is still working.

Configuring the newrelic.appname settings – Apache
From from command line/shell, cd into /var/cpanel/templates/apache2_2 (or whichever version of Apache you are running) and copy vhost.default to vhost.local (cp vhost.default vhost.local) if there isn’t already a vhost.local file. Now open that file up in your favourite text editor (for simplicities sake, I’m using nano : nano -w /var/cpanel/templates/apache2_2/vhost.local).

Near the top of the file it will say something like:

<VirtualHost[% FOREACH ipblock IN vhost.ips %] [% ipblock.ip %]:[% ipblock.port %][% END %]>
ServerName [% wildcard_safe(vhost.servername) %]
[% IF vhost.serveralias_array.size -%]
[% FOREACH alias IN vhost.serveralias_array -%]
ServerAlias [% alias %]
[% END -%]

Add a suitable “SetEnv newrelic_appname” line. For example, I want all of the sites to be recorded against the main virtual host’s server name, so I would use:

<VirtualHost[% FOREACH ipblock IN vhost.ips %] [% ipblock.ip %]:[% ipblock.port %][% END %]>
ServerName [% wildcard_safe(vhost.servername) %]
SetEnv newrelic_appname [% wildcard_safe(vhost.servername) %]
[% IF vhost.serveralias_array.size -%]
[% FOREACH alias IN vhost.serveralias_array -%]
ServerAlias [% alias %]
[% END -%]

You could also use the user’s username SetEnv newrelic_appname [% % vhost.user %] if you wanted to.

Use the Distiller to check everything looks good:
/usr/local/cpanel/bin/apache_conf_distiller --update
and if it does, rebuild the Apache configuration:
/usr/local/cpanel/bin/build_apache_conf
and again restart Apache and test.

Now, there is an environment variable called “newrelic_appname” available for usage. But we’re not using it yet: so we move onto:

Configuring the newrelic.appname settings – PHP
Using a <?php phpinfo(); ?> script find where your php.ini file – ours was in /usr/local/lib/php.ini . Open it open in your text editor again (nano -w /usr/local/lib/php.ini) and search for the newrelic.appname setting which should appear (Press Ctrl+W and then type appname in nano). You should see something like:

; Setting: newrelic.appname
; Type : string
; Scope : per-directory
; Default: “PHP Application”
; Info : Sets the name of the application that metrics will be reported into.
; This can in fact be a list of up to 3 application names, each of
; which must be separated by a semi-colon. The first name in any such
; list is considered the ‘primary’ application name and must be unique
; for each account / license key.
;
;newrelic.appname = “PHP Application”

;
; Beginning with version 3.0 of the agent, the daemon can be automatically
; started by the agent. There is no need to start the daemon before starting

Remove the colon and the start of the line and change it to read from ${newrelic_appname} for example:

; for each account / license key.
;
newrelic.appname = “${newrelic_appname}”

;
; Beginning with version 3.0 of the agent, the daemon can be automatically

This will read in the newrelic_appname environment variable upon run and dynamically replace it in the PHP settings. Restart Apache again (just to be safe) and check a few sites are working. Within a couple of minutes, you should see the records appear in NewRelic.

All done! Have fun!