PHP overriding “Soapaction” header

Oh no, SOAP again. I hate SOAP…. but making shit work is everyone’s job. So, here i go again. This time i need (don’t ask why) to change the Soapaction header. It turns out to be quite simple with the bundled Soap extension of PHP. Just need to extend the SoapClient and override the  __doRequest function. The code:

<?

class CustomSoapClient extends SoapClient {
  function __doRequest($request, $location, $action, $version, $one_way = 0) {
    $action = 'my_custom_soap_action'; // override soapaction here
    return parent::__doRequest($request, $location, $action, 
                               $version, $one_way);
  }
}


$options = array('exceptions'=>true,
                 'trace'=>1,
                 'cache_wsdl'=>WSDL_CACHE_NONE
                 );
            
$client = new CustomSoapClient('my.wsdl', $options);

try {
  $input = new stdClass();
  $input->property  = "example";
  $input->property2 = "example2";
   
  $response = $client->helloWorld($input);   
   
} catch (Exception $e) {
  echo "\n";
  echo 'Caught exception: ',  $e->getMessage(), "\n";
  echo "\n";
  echo "REQUEST:\n" . $client->__getLastRequestHeaders() .
                      $client->__getLastRequest() . "\n";
  echo "\n";
  echo "RESPONSE:\n" . $client->__getLastResponseHeaders() . 
                       $client->__getLastResponse() . "\n";   
}			
			
?>

WordPress – Translated frontend with backoffice in English

Last days, i had to mess around with the excelent blog and publishing software WordPress. I wanted the frontend localized in portuguese (yes… one or other of my projects are not globe wide), so i downloaded the portuguese version, but the administration backoffice also gets translated, and it looks pretty lame in portuguese.

The localization in WordPress is (more or less) pretty straightforward. It’s gettext based, so a translated version is just the same as the usual with a corresponding .mo and .po file in wp-includes/languages/ directory. Then you set the corresponding WPLANG constant in wp_config.php file. But it’s all or nothing, you get both the frontend and the backoffice translated….

But quickly i found myself a solution and i was happy again with an english backoffice. It just needs a tweak in the apache virtualhost configuration to set up an environment variable fot the backoffice that can be tested in wp-config.php file.

The apache config:

</Directory "/usr/home/wordpress/">
    AllowOverride None
    Order deny,allow
    Allow from all

    RewriteEngine On
    RewriteRule ^wp-login\.php - [E=BO:true]
    RewriteRule ^wp-admin/.* - [E=BO:true]
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . %{DOCUMENT_ROOT}index.php [L]
</Directory>

So, all the requests to wp-login and wp-admin (the backoffice administration interface) get the BO variable, now just need to test it and apply the WP_LANG only to all other requests in wp-config.php:

if (! (isset($_SERVER['BO']) && $_SERVER['BO']))
    define ('WPLANG', 'pt_PT');

There, frontend translated and backoffice in good old english tech words.

PS
I needed to adjust some translated strings, but found the .po file without translated strings (like a .pot file). But no problem you can generate a .po file from the .mo file, just run:

msgunfmt pt_PT.mo > pt_PT.po

URL/File decoupling with Apache mod_rewrite and PHP

In the beginning God created the heavens and the earth, then there was the Apache HTTP Server and afterwards PHP. Back in those ages, i was split between CGIs and mod_php. So the usual URL was something as http://www.mydomain.com/cgi-bin/script.pl?do=this or http://www.mydomain.com/script.php?do=that. It was simply a direct link between script.pl and script.php and a file in the filesystem … also it was ugly as hell…

I was not happy with this at all… and besides, just to make my days more miserable, some websites had perfect URLs, like:

http://www.mydomain.com/product/my_product
http://www.mydomain.com/product/my_other_product

so… i put myself to work to emulate this. First, i tried, to use a directory system and take advantage of the auto-index feature, as the index file is automatically served by the server. Ex:

http://www.mydomain.com/product/my_product/index.html
http://www.mydomain.com/product/my_other_product/index.html

but you could actually access them the way i wanted

http://www.mydomain.com/product/my_product
http://www.mydomain.com/product/my_other_product

This was of course a bad nightmare to maintain, not even to speak about database driven websites and related problems, template problems… nightmare…. So, i moved along to PHP auto prepend feature, the idea was to catch the user request by a php file (that is prepended to each request) do all the parsing and display and then kill the normal page processing. Better, but not quite there yet….

Then i discovered Apache mod_rewrite, and everything made sense, all things, the universe, the meaning of life, even Flash programming (well maybe not Flash programming). With some simple rules i was able to catch the user request and filter the ones that i wanted to a central file (that i call handler.php) parse the request and send it to whatever file/module that i want.

RewriteEngine on
RewriteCond %{REQUEST_URI} !\.(php|xml)$ [NC]
RewriteRule \.[a-z0-9]{1,}$ - [NC,L]
RewriteRule .* %{DOCUMENT_ROOT}/handler.php [L]

What are we doing here is quite simple but at the same time powerful. With these rules, all requests with file extension (.gif, .png, .js, .css, etc, etc), usually static content, are directly served as normal (line 3), except for the requests with .php and .xml extension that are sent to the “handler.php” (line 2), if we want other extensions to be sent to dynamic parsing, ex: server side generated image, just add them in this line.

Then a stripped down handler.php file is something like this

// configurations
require('config/vars.inc.php');
require('config/bd.inc.php');

// session start
session_name(SESSION_NAME);
session_start();

// outputt buffering
ob_start();
  
// get script parts
$uri = $_SERVER['REQUEST_URI'];
$tmp = explode ("?", $uri);
if (! isset($tmp[0])) $tmp[0] = '/';
$script_parts = explode ("/", $tmp[0]);

// clean empty keys
$tmp = array();
foreach($script_parts as $key=>$row)
  if ($row != '') $tmp[] = $row;
$script_parts = $tmp;

// default
if (! isset($script_parts[0])) 
  $script_parts[0] = 'hp';

// Send to execution
switch ($script_parts[0]) {
  case 'hp':
    require($_SERVER['DOCUMENT_ROOT'].'/homepage.php');
    break;
		
  case 'products':
    if (isset($script_parts[1])){
      require($_SERVER['DOCUMENT_ROOT'].'/modules/products/detail.php');
      break;
    }	
		
    require($_SERVER['DOCUMENT_ROOT'].'/modules/products/cat.php');
    break;
		
  case 'php':
    phpinfo();
    break;
		
  default:  // 404 error (not found)
    header("HTTP/1.0 404 Not Found");
    require($_SERVER['DOCUMENT_ROOT'].'/templates/error404.php');	
}

Simple, include all the global stuff, start sessions, database links, etc… get the URL request, parse it and send it to whatever file for processing. But as always you can/should build from here, change it to your needs and/or style, put your secret ingredient, do it better for yourself.

Some (many) years ago i would kick some ass to read this post and get this info on a silver plate.

PHP regexp replace word(s) in html string if not inside tags

The problem, was to find and replace text inside HTML (without breaking the HTML), take for example this example string:

<img title=”My image” alt=”My image” src=”/gfx/this is my image.gif”><p>This is my string</p>

and you want to replace the string “my” to another string or to enclose it inside another tag (let’s assume <strong></strong>), but only the “my” outside the html tags. So after the transformation it would look like:

<img title=”My image” alt=”My image” src=”/gfx/this is my image.gif”><p>This is <strong>my</strong> string</p>

With PHP Regular Expression functions, the typical solution find and replace with word boundary fails here.

preg_replace('/\b(my)\b/i',
             '<strong>$1</strong>',
             $html_string);

you will end up with messed up html

<img title=”<strong>My</strong> image” alt=”<strong>My</strong> image” src=”/gfx/this is <strong>my</strong> image.gif”><p>This is <strong>my</strong> string</p>

now think the wonderful mess that would be if you are replacing the words like “form” or “alt” that can be a text node, a html tag or attribute….

So how to fix this? I figured that the only common thing to all tags is the open and close character, the < and >, from here you simply search the word you want to replace and the next close tag char (the > sign), and within the matched result, you try to find a open tag char, if you don’t find an open tag you are within a tag, so you abort the replace. Here it is the code:

function checkOpenTag($matches) {
    if (strpos($matches[0], '<') === false) {
        return $matches[0];
    } else {
        return '<strong>'.$matches[1].'</strong>'.$matches[2];
    }
}

preg_replace_callback('/(\bmy\b)(.*?>)/i',
                      'checkOpenTag',
                      $html_string);

If you are going to use this kind of code to implement several words search in a HTML text (ex: a glossary implementation) test for performance and do think about a caching system.

That’s it, remember as this solution worked fine for me, it also can work terribly bad for you so proceed at your own risk (aka liability disclaimer).

UPDATE 19-04-14
There was a comment about this post that warms about only the first occurrence being replaced in an HTML segment. So, there is an updated version of the PHP example with this issue corrected:

<?

class replaceIfNotInsideTags {

  private function checkOpenTag($matches) {
    if (strpos($matches[0], '<') === false) {
      return $matches[0];
    } else {
      return '<strong>'.$matches[1].'</strong>'.$this->doReplace($matches[2]);
    }
  }

  private function doReplace($html) {
    return preg_replace_callback('/(\b'.$this->word.'\b)(.*?>)/i',
                                 array(&$this, 'checkOpenTag'),
                                 $html);
  }

  public function replace($html, $word) {
    $this->word = $word;

    return $this->doReplace($html);
  }
}

$html = '<p>my bird is my life is my dream</p>';

$obj = new replaceIfNotInsideTags();
echo $obj->replace($html, 'my');

?>