cjhaas.com

WordPress command line (WP-CLI) and proc_open

Posted in WordPress,WP-CLI by Chris Haas on July 30th, 2014

WP-CLI is an awesome command line tool to manage your WordPress installation. You can view plugin information, perform plugin or core updates and show the current cron tasks. This is great for both system administrators who don’t always have user accounts within WordPress as well as WP admins who don’t want to fire up a browser to perform these tasks.

Unfortunately, some hosts lock out certain commands from running for security reasons. Things like shell_exec and proc_open are usually on this list. PHP itself had an option called “Safe Mode”, which although it has been deprecated, shows that there was time when this was needed or at least requested by the community. In a perfectly setup system these commands don’t need to be disabled. If you know you have a perfectly setup system, this post isn’t for you. For the rest of us that think we might have a perfectly setup system but wouldn’t place bets on it because we’ve been on the web long enough to remember attack after attack after attack after attack after attack, this post might be for you. If you try to run WP-CLI on a system that has proc_open disabled you might get fatal error like this:

Warning: proc_open() has been disabled for security reasons

You might think to yourself, “well, I guess I can’t use WP-CLI then” and you’d actually be very wrong (or at least mostly very wrong). WP-CLI uses proc_open for a couple of things but most commands don’t use it at all. In fact, the command that uses it most is the help command and it only uses it to format the text on the screen (by piping over to less). I submitted a patch for this but it was rejected because it was considered an edge case which I respect. I listed the commands that require proc_open here but I’ll list them below, too.

  1. wp db * – Absolutely everything in db depends on it
  2. wp core download does unless you specify and pre-create --path so that still works. This could be changed over to use wp_mkdir_p possibly
  3. wp post create --edit – Attempts to launch your editor which won’t work and there’s no way around that
  4. wp rewrite structure requires it to launch wp rewrite flush but you can still manually invoke the latter command. (This is the only command I could find that uses the launch_self helper, too)
  5. wp plugin delete requires it to delete the folder recursively and forcfully. Seems like the _rmdir from the core command could just be reused
  6. wp plugin update requires it only if --version=dev is passed to it
  7. wp help – Pipes to less on non-Windows systems

So two entire commands, db and help, two specific parameter versions, wp post create --edit and wp plugin update --version=dev and three broken unless you know the work around, wp core download, wp rewrite structure and wp plugin delete.

Most of the items above work, you just need to do some extra work, but it’s the last one that’s just weird. The entire help subsystem won’t work because they’re using a system call to format the text onto multiple pages. Let me say that again, almost all commands work, only the help system won’t. Luckily this is a relatively easy fix, just download the source, apply the patch and rebuild the phar.

Disable WordPress’s cron for XML-RPC requests

Posted in Plugins,WordPress by Chris Haas on July 28th, 2014

WordPress has a custom task scheduler that gets fired on every single request to a WordPress site. By “fired” I mean that every request involving WordPress causes a lookup to see if there are any tasks waiting to be run and if so runs them. The tasks are actually run by the server sending itself an HTTP POST asynchronously in the background. This is a pretty nifty way of handling tasks, especially since allowing a page to ask a server to run a scheduled task could expose some ugly security problems across the supported platforms. If you’ve got a high traffic site, however, you might want to disable WordPress’s built-in cron system and manually create a cron job on the server that runs at intervals of your own choosing. You can see an example here for cPanel-based installations that should pretty easily translate across platforms. For Windows I’d recommend either using PowerShell which actually has a command called Invoke-WebRequest with two aliases, curl and wget. If you don’t want to use PowerShell then I’d recommend just downloading either wget or curl from a trusted source.

Recently, however, there’s been some big attacks on WordPress’s XML-RPC and XML-RPC actually still invokes WordPress’s task scheduler the same as a normal request. If you have a stuck or malformed task this can result in every XML-RPC request firing a second HTTP POST to your server thus doubling your traffic. The recommended fix is to look through and audit all of your cron tasks. WordPress doesn’t have a built-in way to do this but, as always, there are plugins for this. I’d recommend WP Crontrol because it always you view, run, edit and delete any tasks.

For a more brute-force method, for instance if you don’t have time to audit your crons or are possibly a system admin without access to WordPress, you can still safely disable XML-RPC for cron jobs. To lookup scheduled tasks WordPress looks for the database option key call cron which holds an array of all of the scheduled tasks. Before getting this option from the database, however, WordPress first kindly asks anyone else if they want to control it by calling the filter `pre_option_cron`. If you return anything other than FALSE the database lookup will be short-circuited. Then, from the cron side of things, if anything other than an array is returned from the option lookup call the cron function aborts. Lastly, XML-RPC calls define a request-level constant called XMLRPC_REQUEST that’s set to TRUE. Putting this all together, you can opt into the filter call for pre_option_cron and return TRUE if that constant is set which will disable cron tasks from running during XML-RPC. The below code shows this off and should work just fine in a theme’s functions.php file.

add_filter(
            'pre_option_cron',
            function( $value )
            {
                //Returning false means to process this request normally.
                //Anything value besides false will be passed directly to the calling function.
                //In our case, _get_cron_array defined in wp-includes/cron.php is the only caller
                //for the cron option and it requires that an array is returned or else it stops (cleanly).
                //Since we're returning the value true we'll safely stop WP's cron from running.
                return defined( 'XMLRPC_REQUEST' ) && true === XMLRPC_REQUEST;
            },
            10,
            1
        );

If you’re running PHP 5.2 or less then you can’t use anonymous functions so you’d want something like this instead:

function vendi_disable_cron_during_xml_rpc( $value )
{
    //Returning false means to process this request normally.
    //Anything value besides false will be passed directly to the calling function.
    //In our case, _get_cron_array defined in wp-includes/cron.php is the only caller
    //for the cron option and it requires that an array is returned or else it stops (cleanly).
    //Since we're returning the value true we'll safely stop WP's cron from running.
    return defined( 'XMLRPC_REQUEST' ) && true === XMLRPC_REQUEST;
}

add_filter(
            'pre_option_cron',
            'vendi_disable_cron_during_xml_rpc'
            10,
            1
        );

If you want to make it easier you can just wrap this into a plugin:

<?php
/*
Plugin Name: Vendi - Disable cron in XMLRPC
Version: 1.0.0
Author: Vendi Advertising (Chris Haas)
Author URI: http://www.vendiadvertising.com/
Description: Disables cron tasks during XMLRPC.
*/

add_filter(
            'pre_option_cron',
            function( $value )
            {
                //Returning false means to process this request normally.
                //Anything value besides false will be passed directly to the calling function.
                //In our case, _get_cron_array defined in wp-includes/cron.php is the only caller
                //for the cron option and it requires that an array is returned or else it stops (cleanly).
                //Since we're returning the value true we'll safely stop WP's cron from running.
                return defined( 'XMLRPC_REQUEST' ) && true === XMLRPC_REQUEST;
            },
            10,
            1
        );

If you are a system admin and cannot log into the WordPress install you can add this plugin as must-use plugin very easily. In the wp-content folder just create another folder called mu-plugins (if it doesn’t already exist) and create a brand new file called disable-cron-for-xml-rpc.php (file name actually doesn’t matter, call it whatever you want) and paste the above plugin code into it. Must-use plugins are auto-activated so you don’t need to log into WordPress however you should probably notify your local WP admin of what you’ve done.

Lastly, if you want to install from a URL you can install from this link

Handling a splitting table in iTextSharp

Posted in iTextSharp,PdfPTable by Chris Haas on July 28th, 2014

The PdfPTable class has a property called TableEvent that can be used to receive (as you would expect), events related to a table. If you’re used to .Net, however, you’ll find that it isn’t a true .Net event that you can += or AddHandler and event onto. Instead, like most (or probably all) of iTextSharp’s events you need to implement a specific interface or possibly subclass a specific class and then pass your specific implementation to that property.

Back to PdfPTable, if you want to receive notifications about table events you want to implement IPdfPTableEvent. One example for why you would want to do this would be to draw a border around a table. When you implement this interface you need a single method called TableLayout that will receive a copy of the table containing just the rows that need to be written out for the current page. If your table splits two pages this method will be called twice.

Another slightly more interesting interface is the IPdfPTableEventSplit which itself implements IPdfPTableEvent. The interesting part is the extra method SplitTable which receives a copy of the entire table, not just the current rows being written. This allows you to write out things like Showing rows XXX of YYY. You can also do other things like disabling headers on the second page or draw extra text.

PHP Base85 encode 128-bit integer (GUID/UUID)

Posted in PHP by Chris Haas on November 12th, 2013

I’m working with GUIDs in PHP and am trying to find the most compact way to represent a 128-bit integer via a string. Searches showed theory and C# code along with a Wikipedia article that referenced many languages except for PHP so I decided to roll my own. The code below relies on having the GNU Multiple Precision extension installed which I’ll leave up to you. You can test this by looking at RFC1924 Section 5 which has the number 21932261930451111902915077091070067066 which encodes to 4)+k&C#VzJ4br>0wv%Yp

  /**
   * Converts a 32-character guid string to a 20-character string using Base85
   *
   * @since  0.3.1
   *
   * @see  http://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html  Hex/Dec/Binary conversion with large numbers.
   * @see  http://tools.ietf.org/html/rfc1924                                   Section 5 has sample 128-bit integers in different formats.
   *
   * @param  string $guid_as_hex_string A guid expressed as a hexidecimal string.
   * @return string                     A 20-character representation of the string encoded as base-85.
   */
  public static function convert_guid_to_base85($guid_as_hex_string){
    //Remove any non-guid characters
    $guid_as_hex_string = preg_replace('/[^0-9A-F]/i', '', $guid_as_hex_string);

    //Not a GUID, fail
    if(strlen($guid_as_hex_string) !== 32){
      return false;
    }

    //Possible characters
    $chars = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
                   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
                   '!', '#', '$', '%', '&', '(', ')', '*', '+', '-', ';', '<', '=', '>', '?', '@', '^', '_', '`', '{', '|', '}', '~'
                  );

    //Build all 20 (nineteen through zero) powers of 85
    $powers = array();
    for($i = 19; $i >= 0; $i--){
      $powers[] = gmp_pow(85, $i);
    }

    //Create our large integer
    $t = gmp_init($guid_as_hex_string, 16);

    //Buf will be our return string, initialize as empty
    $buf = '';

    //Loop through each power in decending order
    foreach($powers as $pow){

      //Divide the current large number by the current power of 85
      //Returns an array, the first element is the integer division of the two, the second is remainder
      $ir = gmp_div_qr($t, $pow);

      //If the result is greater than or equal to 1
      if(gmp_cmp($ir[0], 1) >= 0){
        //Get the character at the integer representation of that position
        $buf .= $chars[gmp_intval($ir[0])];
      }else{
        //Otherwise get the character at the zero position
        $buf .= $chars[0];
      }

      //Reset our large number to just the remainder of the division
      $t = $ir[1];

      //Repeat
    }

    return $buf;
  }

This code isn’t getting run a million times per day so for future reading purposes I’m building the power array manually. The long form of it would be

    $powers = array(
                    gmp_pow(85, 19),
                    gmp_pow(85, 18),
                    gmp_pow(85, 17),
                    gmp_pow(85, 16),
                    gmp_pow(85, 15),
                    gmp_pow(85, 14),
                    gmp_pow(85, 13),
                    gmp_pow(85, 12),
                    gmp_pow(85, 11),
                    gmp_pow(85, 10),
                    gmp_pow(85,  9),
                    gmp_pow(85,  8),
                    gmp_pow(85,  7),
                    gmp_pow(85,  6),
                    gmp_pow(85,  5),
                    gmp_pow(85,  4),
                    gmp_pow(85,  3),
                    gmp_pow(85,  2),
                    gmp_pow(85,  1),
                    gmp_pow(85,  0),
                  );

And if you really want to optimize things (possibly) then you can just use the actual numbers. I didn’t bother testing perf on gmp so I don’t know (or care) what’s faster, math or string parsing.

    $powers = array(
                    gmp_init('4559944833472277161543903350830078125', 10),
                    gmp_init('53646409805556201900516510009765625', 10),
                    gmp_init('631134233006543551770782470703125', 10),
                    gmp_init('7425108623606394726715087890625', 10),
                    gmp_init('87354219101251702667236328125', 10),
                    gmp_init('1027696695308843560791015625', 10),
                    gmp_init('12090549356574630126953125', 10),
                    gmp_init('142241757136172119140625', 10),
                    gmp_init('1673432436896142578125', 10),
                    gmp_init('19687440434072265625', 10),
                    gmp_init('231616946283203125', 10),
                    gmp_init('2724905250390625', 10),
                    gmp_init('32057708828125', 10),
                    gmp_init('377149515625', 10),
                    gmp_init('4437053125', 10),
                    gmp_init('52200625', 10),
                    gmp_init('614125', 10),
                    gmp_init('7225', 10),
                    gmp_init('85', 10),
                    gmp_init('1', 10),
                  );

Add additional keys to WP Remote

Posted in Plugins,WordPress by Chris Haas on November 7th, 2013
/**
 * Add aditional API keys
 */
add_filter('wpr_api_keys', 'vendi__wpr_api_keys');
function vendi__wpr_api_keys($keys){
    if(!is_array($keys)){
        $keys = (array)$keys;    //The stored key is probably a string literal so turn it into an array
    }
    $keys[] = 'SECOND_KEY_HERE'; //Make a note so you know what it was
    $keys[] = 'THIRD_KEY_HERE';  //Make a note so you know what it was
    return $keys;                //Return the above changes
}
Tagged with:

Additional string formatting for $wpdb->insert

Posted in WordPress by Chris Haas on November 5th, 2013

I really like using the helper $wpdb class for inserts but occasionally I have a need to insert data using more than just %s, %d or %f format strings. Almost everyone will tell you to manually write your own INSERT statement and then just pass that to $wpdb->prepare() (which $wpdb->insert() does for you) but there is another way!

And it is actually documented in the code! Kind of. In wp-db on line 1307 (as of WP 3.7.1) it says:

A format is one of ‘%d’, ‘%f’, ‘%s’ (integer, float, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.

The $wpdb has a member variable called $field_types which is an associative that you can use to override the formatting. To use it you cannot specify any formatting parameters when calling insert.

In my case, I had a need insert a GUID-like string into binary(16) column using the UNHEX() MySQL function.

global $wpdb;

//Set out override (anything not specified will be treated as %s)
$wpdb->field_types['transaction_id'] = "UNHEX('%s')";

//Call the normal insert
$wpdb->insert(
             $wpdb->payments,
             array(
                   'transaction_id' => $transaction_id,
                   'name'           => $name
                  )
             );

//Be polite, reset the array just in case future statements are run on this with the same column names
$wpdb->field_types = array();
Tagged with:

CSS Transitions not working first time in Firefox and Internet Explorer

Posted in Uncategorized by Chris Haas on May 24th, 2013

I was doing some simple CSS transitions like transition: left 0.5s ease-in-out 1 and they were working just fine in Chrome but Firefox and Internet Explorer either wouldn’t use the transitions or they wouldn’t work the first time but subsequent times they would. So if I had an arrow that moved something the first click would jump the object while every click after the object would slide.

Simple fix, I wasn’t giving the object an initial value. I thought (incorrectly) that left and top were defaulted to 0 but really they’re null (or whatever CSS’s equivalent of null is).

So I had a declaration like:

#obj{position:absolute;transition: left 0.5s ease-in-out 1;}
#obj:hover{left:-100px;}

But since I never declared left:0 in the first line Firefox and Internet Explorer won’t transition the property. The transition not working the first time but all subsequent times was the same thing, I was setting an initially null property via JavaScript so the first time those browsers had nothing to transition from. Once set they did and everything worked fine.

So moral of the story, if you transition a property, make sure you give it an initial value, too.

UPDATE

Well, the above gets you almost there. You also need to make sure that your timing values also specify their unit. Instead of just 1 or even 0 you need to specify 1s or 0s. Firefox apparently doesn’t have a default unit (even for zero apparently).

#obj{position:absolute;transition: left 0.5s ease-in-out 1s;}
#obj:hover{left:-100px;}
Tagged with:

DO NOT SEND ME MY PASSWORD. EVER!!!

Posted in Uncategorized by Chris Haas on May 17th, 2013

I can’t believe anyone would actually transmit a password in the clear in this day and age. Especially a tech(-ish) company. Just signed up for an API key at a screen shot place (won’t name but people can guess) and they sent me my password via email. Thank you for passing that through untold servers and logging systems!

*** failed to import extension kilnauth from ~/KilnExtensions/kilnauth.py: invalid syntax

Posted in Uncategorized by Chris Haas on April 18th, 2013

You might run into this error message if you’ve got an older version of python installed. The problem is the newer with syntax:

        with open(self.__temporary_path, 'r') as f:
            before = md5(f.read()).digest()

The solution is to just convert it to try/finally

        f = open(self.__temporary_path, 'rb')
        try:
            before = md5(f.read()).digest()
        finally:
            f.close()

MySqlDump to individual files and restoring again

Posted in mysql by Chris Haas on April 17th, 2013

Make sure that your mysql user has permission to access the file system (the FILE privilege). GRANT ALL does not do this. You can check your user by doing:

select user, host, file_priv from mysql.user;

To enable:

grant FILE on *.* to 'root'@'localhost';flush privileges;

Also make sure that mysqld can write to the specified folder (./sql below). To dump:

mysqldump -uroot -p your_database --tab=./sql

Importing back is a two step process, DDL first followed by tab-delimited data:

DDL

cat sql/*.sql | mysql -uroot -p your_database

Tab delimited data

NOTE: The path you provide MUST be absolute. Nevermind, you can use --local to fix
NOTE: The -d parameter means DELETE from the current table before importing!

mysqlimport --local -uroot -p -d your_database sql/*.txt

Additionally, you might want to de-domain your files (for instance, if you’re backing up a WordPress site)

find sql/ -type f -name '*.txt' -exec sed -i 's/old_domain.com/place_holder/g' {} \;