Ubuntu 12.04 Nginx MariaDB Php

I just wrote an article about Nginx & PHP 54 fpm on irtbf posterous site

Activate full log MariaDB/Mysql

  1. Set the log filename
    db001 [(none)]> SET GLOBAL general_log_file = '/var/log/mysql/full.log';
  2. activate full log
    db001 [(none)]> SET GLOBAL general_log = 'ON';
  3. deactivate full log
    db001 [(none)]> SET GLOBAL general_log = 'OFF';

credit: Michaël

XPdev hot seat at work experience learned

I proposed new objectives to myself:
Programming in XP (hot seat: 2 dev one computer) 1/2 day per week with another developer each week.
Here is a summary of DOs and DONTs to keep in mind.

Let’s say there are 2 guys:

  • Tori: the executor (the guy who have the keyboard and explain what he does)
  • Uke: the learner (the guy who look at the guy who have the keyboard and learn from what he does)
DO DON’T
Explain the whole concept of XP hot seat, Tori & Uke roles and plan it Start without briefing, scheduled appointment
Predefine the scope 1 day before start without plan
Master the concept of the scope do a spike in XP as it request a lot of documentation reading
Read the documentation the day before Drive blind
Use shortcuts, quick links, snippets, auto completion, syntax highlighting Use notepad or similar way of development
Refine and reduce objective and scope while working Enlarge the scope and work on more and more stuff
Let Tori explain what he is doing Let Uke take the lead
Respect the time window of 15 minutes Let Tori continue over 15 minutes
Stop and re-schedule, redefine scope when it fails (both get stuck by a lack of knowledge for instance) Continue if it doesn’t work

Upgrading from ubuntu 11.10 to 12.04LTS

Same issue. In system settings: clicking on Network raise a popup with: The system network services are not compatible with this version…

No network at all

cat /etc/interfaces
auto lo
iface lo inet loopback

Gasp.

update 1 hour later

Problem solved.
Obviously the upgrade process crashed somewhere, I clicked the “Updates Available…” menu item from the top right computer menu and ran a partial upgrade which finished successfully the 12.04 install and restarted the network.
I guess the X server failed during the night waiting for me to click a dialog box. This morning the screen was dark and the pc was running, but with no answer from the keyboard I thought he hanged at the restart stage… but it was at the config stage somewhere.

Everything back to normal. Resuming normal activities.

end of transmission

Mysql 5.5.20 utf8 collation bug with implicit datetime casting

A very strange behavior detected in Mysql 5.5.20 maybe linked to some implicit cast/convert: The datetime is implicitly converted to the next day…

it’s a morning bug, solved every afternoon and detectable thus only in the morning, probably an AM/PM error while working in 24h…

That’s a really stupid bug that makes me waste half a day so I post it here, just in case someone has the same issue.

It did not exist in 5.1 and does not exist in MariaDB, so it’s probably something added by Oracle somewhere in between…

Here is the query with a between date, with the standard connection settings:

show variables like 'character%';
+--------------------------+---------------------------------------+
| Variable_name            | Value                                 |
+--------------------------+---------------------------------------+
| character_set_client     | latin1                                |
| character_set_connection | latin1                                |
| character_set_database   | utf8                                  |
| character_set_filesystem | binary                                |
| character_set_results    | latin1                                |
| character_set_server     | utf8                                  |
| character_set_system     | utf8                                  |
| character_sets_dir       | /opt/mysql/server-5.5/share/charsets/ |
+--------------------------+---------------------------------------+
SELECT * 
FROM tableA A 
WHERE (A.`end_date` >= '2012-04-27T07:04:25+02:00') 
AND (A.`start_date` <= '2012-04-28T06:30:00+02:00' );
| id    | start_date          | end_date            |
| 42966 | 2012-04-27 19:50:00 | 2012-04-27 22:55:00 |
| 36883 | 2012-04-27 23:00:00 | 2012-04-27 23:50:00 |

Trying with the settings switched to utf8 still works.

SET NAMES utf8;
SELECT * 
FROM tableA A 
WHERE (A.`end_date` >= '2012-04-27T07:04:25+02:00') 
AND (A.`start_date` <= '2012-04-28T06:30:00+02:00' );
| id    | start_date          | end_date            |
| 42966 | 2012-04-27 19:50:00 | 2012-04-27 22:55:00 |
| 36883 | 2012-04-27 23:00:00 | 2012-04-27 23:50:00 |

And then, TADAAA the bug, with implicit casting while using the collate utf8_unicode_ci.

SET NAMES utf8 COLLATE utf8_unicode_ci;
SELECT * 
FROM tableA A 
WHERE (A.`end_date` >= '2012-04-27T07:04:25+02:00') 
AND (A.`start_date` <= '2012-04-28T06:30:00+02:00' );
| id    | start_date          | end_date            |
| 37093 | 2012-04-28 17:50:00 | 2012-04-28 20:00:00 |
| 31003 | 2012-04-28 19:55:00 | 2012-04-28 22:00:00 |
| 43181 | 2012-04-28 20:00:00 | 2012-04-28 22:59:00 |
| 43112 | 2012-04-28 22:45:00 | 2012-04-28 23:59:00 |

So let’s try with an explicit conversion… and it works.

SET NAMES utf8 COLLATE utf8_unicode_ci;
SELECT * 
FROM tableA A 
WHERE (A.`end_date` >= TIMESTAMP('2012-04-27T07:04:25+02:00')) 
AND (A.`start_date` <= TIMESTAMP('2012-04-28T06:30:00+02:00') );
| id    | start_date          | end_date            |
| 42966 | 2012-04-27 19:50:00 | 2012-04-27 22:55:00 |
| 36883 | 2012-04-27 23:00:00 | 2012-04-27 23:50:00 |

If anyone can spot the real bug and explain it to me… I’m listening.

HTTP xml POST in php with curl or with Zend

<?php

/**
 * Send xml via HTTP
 */

// Create XML

$xml = <<<EOF
<?xml version="1.0"?>
<xmlsample>
	<title>Test</title>
	<url>http://www.example.org/</url>
	<!-- 
		This is a comment
	-->
</xmlsample>

EOF;

print("We will send this xml: \n$xml");

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:8080/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_USERAGENT, "MyUserAgent/1.1");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if($result===false){
	print("Error: ".curl_error($ch));
}else{
	print("Success");
}
curl_close($ch);

To test the code just launch a nc:

nc -l localhost 8080

and run your script from a browser or with php in command line.

Here is the same code using Zend Framework.

require_once("Zend/Http/Client.php");
$client = new Zend_Http_Client('http://localhost:8080/upload.php');
$client -> setAdapter("Zend_Http_Client_Adapter_Curl");
$client -> setHeaders('User-Agent',"MyUserAgent/1.1");
try{
	$client->setRawData($xml, 'text/xml')->request('POST');
}catch(Exception $e){
	print("Error: ".var_export($e,true));
}

Mysql 5.5 problem with date using php PDO and ‘slashes’ instead of ‘dashes’


While upgrading from mysql 5.1 to mysql 5.5 we found a strange issue.

Consider the DB testdb and the TABLE test

CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `date_insert` datetime NOT NULL,
  KEY `index_date` (`date_insert`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

We have an issue with date and collate settings:

For instance: This will return nothing

SET NAMES utf8 COLLATE utf8_unicode_ci;
SELECT COUNT(*) FROM testdb.test WHERE date_insert&gt;'2012/02/01';

but this will work

SET NAMES utf8 COLLATE utf8_general_ci;
SELECT COUNT(*) FROM testdb.test WHERE date_insert&gt;'2012/02/01';

We are still checking why… but at least we have a quick fix.

A better fix is to use an ISO 8601 date:
2012-02-22T00:00:00+01:00

This will work regardless of the COLLATE option

SET NAMES utf8 COLLATE utf8_unicode_ci;
SELECT COUNT(*) FROM testdb.test WHERE date_insert&gt;'2012-02-22T00:00:00+01:00';

A similar solution is to use ‘-’ (dash) instead of ‘/’ (slash) in all date:

SET NAMES utf8 COLLATE utf8_unicode_ci;
SELECT COUNT(*) FROM testdb.test WHERE date_insert&gt;'2012-02-22';

That’s probably a better practice anyway.

Bière Ommegang


Au début je n’y ai cru qu’a moitié. Puis j’ai oublié…
Il y a quelques jours j’ai reçu un mail pour me dire que le brassin était pret et que dès que l’embouteillage aurait lieu, la bouteille serait envoyée.
Là je me suis dit: “ça doit être une erreur, ils ont envoyé un mail à tout le monde alors qu’ils ne ciblait que les acheteurs”.
Mais, je dois me rendre à l’évidence, car c’est bien arrivé. Aujourd’hui j’ai été chercher au point poste ma bouteille d’Ommegang édition limitée.
Waw… ça c’est du marketing!
Pas de spam, un message pour dire que ça va arriver et puis le cadeau. Propre, simple efficace.
Bon, il ne reste plus qu’à gouter.

Calling XmlRpc of WordPress with Zend Framework (Zend_XmlRpc_Client) and adding the default thumbnail to a post

This code is in 2 parts

First part, we download an image somewhere using Zend_Http_Client

Second part, we use xmlrpc to upload the image into wordpress as a media and to create a post using this media as featured image or default image of main thumbnail, whatever the name is

Let’s have a look at the first part:
Downloading an image with Zend_Http_Client
this is quite simple

				require_once 'Zend/Http/Client.php';
				$config=array(
					'adapter'=>'Zend_Http_Client_Adapter_Curl'
				);
				$Zend_Http_Client = new Zend_Http_Client($imageUrl,$config);
				try{
					$result = $Zend_Http_Client->request('GET');
				}catch(Exception $e){
					print_r($e);
				}
				$data = $result->getBody();
				//file_put_contents('/tmp/test.jpg',$data); // this is just to test the image if you are unsure

second part, storing the image in wordpress and creating a post with custom field: _thumbnail_id set to this image

To store a media object we will use the metaWeblog.newMediaObject XmlRpc method

				require_once 'Zend/XmlRpc/Client.php';
				require_once 'Zend/XmlRpc/Value/Base64.php';
				require_once 'Zend/XmlRpc/Value/Struct.php';
				require_once 'Zend/XmlRpc/Value/Array.php';
				$xmlRpcClient = new Zend_XmlRpc_Client('http://www.example.com/myblog/xmlrpc.php');
				try{
					$thumbnail = $xmlRpcClient->call(
						'metaWeblog.newMediaObject',
						array(0,
							'login',
							'pass',
							array(
								'name'=>'test.jpg',
								'type'=>'image/jpeg',
								'bits'=>new Zend_XmlRpc_Value_Base64($data),
							)
						)
					);
// ...

in the thumbnail object we don’t get the id… because it’s not possible to get the id unless you hack wordpress

WP file: wp-include/class-wp-xml-rpc.php

method: function mw_newMediaObject($args) {

modification: add the id in the return:

return apply_filters( 
	'wp_handle_upload', 
	array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type )
	, 'upload' 
	);

by:

return apply_filters( 
	'wp_handle_upload', 
	array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type, 'id'=>$id )
	, 'upload' 
	);
// ...
		$struct = new Zend_XmlRpc_Value_Struct(
					array('key'=>'_thumbnail_id', 'value'=>$thumbnail['id'])
				);
		$result = $xmlRpcClient->call(
			'metaWeblog.newPost',
			array(0,
			'login',
			'pass',
			array(
				'post_type'=>'post',
				'title'=>'New article with thumb',
				'description'=>'Article text',
				'custom_fields'=>array($struct),
			),
			false)
		);
	}catch(Exception $e){
		print_r($e);
	}

Of course, this won’t work… because no one is allowed to access private custom_fields such as _thumbnail_id …

A second WP hack is necessary here:

file: wp-includes/meta.php
function: is_protected_meta

add an exception for _thumbnail_id

function is_protected_meta( $meta_key, $meta_type = null ) {
        if($meta_key == '_thumbnail_id'){
                $protected=false;
        }else{
                $protected = (  '_' == $meta_key[0] );
        }
        return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}

Without a nice documentation that was the best I could do in few time.

Another approach could be to create a new XmlRpc method, which do both in once avoiding the weakness of reusing an internal id in a second call, but still XmlRpc use add_meta which is a really ugly way to add meta in a post as everything has to be put in $_POST …

If anyone has a better approach (using xmlrpc) feel free to submit the suggestion.

A third approach could be to write a plugin… that’s next step

All the assumption I want to remember in PHP

Probably linked to some alcohol I drank to young, I always forget some key assumption in PHP.

NULL is NULL
NULL is EMPTY
NULL is FALSE
NULL has a sizeof 0

BUT

FALSE is not NULL
FALSE is EMPTY
FALSE is FALSE
FALSE has a sizeof 1

AND

empty ARRAY is not NULL
empty ARRAY is EMPTY
empty ARRAY is FALSE
empty ARRAY has a sizeof 0

$test=NULL;
if(is_null($test)){print("NULL is NULL");}else{print("NULL is not NULL");}
// NULL is NULL
if(empty($test)){print("NULL is EMPTY");}else{print("NULL is not EMPTY");}
// NULL is empty
if($test){print("NULL is TRUE");}else{print("NULL is FALSE");}
// NULL is FALSE
print(count($test));
// 0
$test=false;
if(is_null($test)){print("FALSE is NULL");}else{print("FALSE is not NULL");}
// FALSE is not NULL
if(empty($test)){print("FALSE is EMPTY");}else{print("FALSE is not EMPTY");}
// FALSE is EMPTY
if($test){print("FALSE is TRUE");}else{print("FALSE is FALSE");}
// FALSE is FALSE
print(count($test));
// 1
$test=array();
if(is_null($test)){print("empty ARRAY is NULL");}else{print("empty ARRAY is not NULL");}
// empty ARRAY is not NULL
if(empty($test)){print("empty ARRAY is EMPTY");}else{print("empty ARRAY is not EMPTY");}
// empty ARRAY is EMPTY
if($test){print("empty ARRAY is TRUE");}else{print("empty ARRAY is FALSE");}
// empty ARRAY is FALSE