Processing Default Namespaces in PHP

I have a rather love hate relationship with XML. I totally understand why it exists and what it is good for, but at the same time it’s really not all that fun to work with in PHP, especially if the XML file has namespaces in it.

So yesterday I was working on some XML that looks kinda like this:

<entry xmlns="http://www.w3.org/2005/Atom">
  <id>urn:publicid:ap.org:7fa2d1ee43834dfdbd036414e852edf9</id>
  <title>Obama US Libya</title>
  <updated>2012-09-12T15:08:31.990Z</updated>
  <published>2012-09-12T15:08:05Z</published>
  <content type="text/plain">
  President Barack Obama speaks in the Rose Garden of the White House in Washington, Wednesday, Sept. 12, 2012.  (AP Photo/Manuel Balce Ceneta)
</content>
  <link rel="enclosure" title="AP Caption" href="http://syndication.ap.org/AP.Distro.ContentBroker2/ContentBroker.aspx?media=text&amp;contentid=2be6785b86d34556bb700753faeedcf1&amp;showInlineLinks=False&amp;recordid=7fa2d1ee43834dfdbd036414e852edf9&amp;authToken=eNoNzDEOwzAIAMAX2QJjMB38liokWMpUS2nlDjw%2bWW%2b48H8XqkqEKsgAoK%2bisZ%2b9mEtTtqRyUKrMkswaJGhMY3M%2f9oHxu%2fr6fuZ7uY2HrpirbxNR4pzPmwtTriWj3gcbHng%3d" length="141" type="text/xml">
    <apcm:Characteristics IngestLink="True" ContentId="urn:publicid:ap.org:2be6785b86d34556bb700753faeedcf1" FileExtension="xml" Format="NITF" MediaType="Photo" MimeType="text/xml" Role="Caption" SizeInBytes="141" Words="23" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" />
  </link>
  <link rel="enclosure" title="AP Photo" href="http://eapcontent.ap.org/jpg/2012/20120912/15/645c1fe2c30bf7191a0f6a706700fbc3.jpg?contentid=645c1fe2c30bf7191a0f6a706700fbc3/fmt=jpg/role=Main/reldt=2012-09-12T15:08:05/media=Photo/recordid=7fa2d1ee43834dfdbd036414e852edf9/authToken=eNoNzMENwyAMAMCJQDYG4zyYpQJqS3kVKYnow8O3N8C5fhtTFiIUxgIAciTxeTbOZaJpCpNgBKt4BOxggXsFrgA2JvlztX1%2f1mvrMNX35Wu3vhDZz%2fV%2fYyoUc4ooP%2f5mHjE%3d&amp;token=1347721815_40CF42661175ACC34B58F8CE0889B78F" length="3388592" type="image/jpeg">
    <apcm:Characteristics IngestLink="True" ContentId="urn:publicid:ap.org:645c1fe2c30bf7191a0f6a706700fbc3" FileExtension="jpg" Format="JPEG Baseline" MediaType="Photo" MimeType="image/jpeg" Role="Main" SizeInBytes="3388592" Digest="6ff2358cd7752497404b450495314b6d" OriginalFileName="Obama US Libya.JPEG" Height="2208" PhotoType="Horizontal" Width="3318" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" />
  </link>
  <link rel="enclosure" title="AP Preview Image" href="http://eapcontent.ap.org/jpg/2012/20120912/15/645c185ec30bf7191a0f6a706700b3e2.jpg?contentid=645c185ec30bf7191a0f6a706700b3e2/fmt=jpg/role=Preview/reldt=2012-09-12T15:08:05/media=Photo/recordid=7fa2d1ee43834dfdbd036414e852edf9/authToken=eNoNzEEOhCAMAMAXQVoKpR54ywbYkniSRA0e%2bnidB4zpU5iiEKEwJgCQLYj1vXBMHSWp6wTNjYybwwrDcc3AGaCRBrvPsq5j%2fpa2ofo%2fba5SJyLbPr%2fXh0Q%2bBo%2fyAukfHdQ%3d&amp;token=1347721815_15CE6F1B74043B3D94E6759D6F05AA80" type="image/jpeg">
    <apcm:Characteristics IngestLink="True" ContentId="urn:publicid:ap.org:645c185ec30bf7191a0f6a706700b3e2" FileExtension="jpg" Format="JPEG Baseline" MediaType="Photo" MimeType="image/jpeg" Role="Preview" Digest="acef0738038f1e1278911923f0786d20" OriginalFileName="Obama US Libya.JPEG" Height="340" Width="512" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" />
  </link>
  <link rel="enclosure" title="AP Thumbnail Image" href="http://eapcontent.ap.org/jpg/2012/20120912/15/645c1701c30bf7191a0f6a7067004cc6.jpg?contentid=645c1701c30bf7191a0f6a7067004cc6/fmt=jpg/role=Thumbnail/reldt=2012-09-12T15:08:05/media=Photo/recordid=7fa2d1ee43834dfdbd036414e852edf9/authToken=eNoNzMENwyAMBdCJQP4YjHNgloq4IOVUpLSiBw%2ffvgGej28TzsoMFRQi0iOp29UkF0MlBGM6w6w4AjrNIL2SVKJsJv65236%2f1mOPc47xvH3t1hcgfq3%2fG1PhmFOE%2fgDZgh2e&amp;token=1347721815_0B1051F4454CC4D183B7EC3D57F1657F" type="image/jpeg">
    <apcm:Characteristics IngestLink="True" ContentId="urn:publicid:ap.org:645c1701c30bf7191a0f6a7067004cc6" FileExtension="jpg" Format="JPEG Baseline" MediaType="Photo" MimeType="image/jpeg" Role="Thumbnail" Digest="26b42c6157bf20c7b8507ed42d8d4eb7" OriginalFileName="Obama US Libya.JPEG" Height="85" Width="128" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" />
  </link>
</entry>

What I needed to get at was the href attributes in those link elements, but only the ones that have a title equal to “AP Photo”. So I figure no problem, I can grab those with xpath pretty easy doing something like this (where $entry is a simplexml object):

$elements = $entry->xpath("//link[@title='AP Photo']/@href");

That should load up an array with the data I need and I can loop through and get the href data. The problem was, it just wasn’t working. As far as I could tell there wasn’t any namespaces getting in the way, but no matter what I tried I just couldn’t get any data out. I started playing around with some online xpath editors and finally pulled out the xmlns=”http://www.w3.org/2005/Atom” bit from the XML. Suddenly, everything worked!

I did a little searching, and it turns out that bit of code created a default namespace. I’m really far more used to namespaces being defined in the root tag and then being able to see the namespace in the XML, more like this:

<apcm:ContentMetadata xmlns:apcm="http://ap.org/schemas/03/2005/apcm">
    <apcm:Priority Numeric="4" Legacy="r" />
    <apcm:ConsumerReady>TRUE</apcm:ConsumerReady>
    <apcm:HeadLine>AP Top News at 11:08 a.m. EDT</apcm:HeadLine>
    <apcm:OriginalHeadLine>AP Top News at 11:08 a.m. EDT</apcm:OriginalHeadLine>
    <apcm:Keywords>NewsBrief</apcm:Keywords>
    <apcm:Cycle>AP</apcm:Cycle>

Either way, now that I knew what I was looking for, it was pretty easy to fix:

$entry->registerXPathNamespace("n", "http://www.w3.org/2005/Atom");
$elements = $entry->xpath("//n:link[@title='AP Photo']/@href");

Just register the namespace for that xpath query and you are good to go!

Manually Sync Two MySQL Databases via SSH

At the office we have a live database and then one we use for development. We don’t want them to sync in real time, because sometimes we need to make changes to the dev version that would break the sync, but at some point we will always need to get the dev version back in sync with the live version. Up until now we’ve been managing that manually by exporting the live database and then importing it into the dev version, which works but is kinda clunky. I got a bit sick of that today and went looking for another solution. After a lot more looking around than I thought it would take, I ran across this post on the 4webby blog.

The ssh command to get the sync done is surprisingly simple:

ssh root@www.liveserver.com “mysqldump -u [user] –password=[pass] [database]” | mysql -u [user] –password=[pass] –host=localhost -C [database]

Just run that from the server you want to sync to, put in the remote password and you are good.

count_all_results() and get_where() in CodeIgniter

This silly little mistake tripped me up for a bit this morning and I only figured it out after some searching. Based on the results I’m not the only person that has hit this roadblock, so here is the solution.

I was doing a normal query that looked something like this:

$read_db = $this->load->database('read', TRUE);
$query = $read_db->get_where(array('username' => $username, 'password' => $password));

Due to some changes in how my application works, I needed to change that from a query that returned a result to a query that just returned the number of items in the query.

So I changed the code above to be:

$read_db = $this->load->database('read', TRUE);
$read_db->get_where(array('username' =>; $username, 'password' =>; $password));
$count = $read_db->count_all_results();

This code would just return a 1 regardless of what the parameters in the where clause were. After a bit of searching I ran across this forum post that told me what the issue was. You should only use get_where() if you actually want to return a result. The correct syntax for this query is:

$read_db = $this->load->database('read', TRUE);
$read_db->where(array('username' => $username, 'password' => $password));
$read_db->from('admin');
$count = $read_db->count_all_results();

This now returns the correct result every time. Silly mistake caused by my misreading the documentation, but it still took a bit to figure it out.

Little Bit of Design

I never have really claimed to be a designer, but occasionally I do a little bit of personal design work, usually for my photography business. I realized at about 4:45 today that I needed signs for a photo shoot we are doing on Friday and Saturday morning and that if I wanted to get them printed I needed them done by 5:00. I’m generally happy with how it came out, although if I print more I’ll probably move the logo down a bit.

I was quite pleased at how easily it was to put together using free icons and backgrounds from the internet. I have the links to the fine people that created the icons and background and them released them for free on my other PC, I’ll have to link to them when I get a second.

 

Today I Made…

Today I started a new personal project that I’m hoping is going to be a lot of fun. Right now I’m calling it “Today I Made”, although I’m not sure that will be final name until I can secure some sort of domain name I like.

The idea of the site is that you will be able to login and post something that you “made”. Made is in quotes because I want to be quite inclusive. For instance, one day I made that image you see up there. Today, I made some nifty CodeIgniter code that lets you upload a file and then drops the content into a database. Maybe tomorrow I’ll make a pie, or paint a picture or build a shelf, who knows? Essentially, I just want people to be able to showcase the things that they actually create by uploading a picture or linking to their blog or just telling everyone about it.

Eventually I hope to add Facebook and Twitter integration, up-voting, badges and all that other Web 2.0 type stuff that every site just needs. But I’ll start simple and build it up as I go and see what people like. I’m hoping that it will give me the chance to build something fun and at the same time get to use some technology that I don’t get to play with all the time at my day job.

Want to follow along as I get going? You can follow along on github here: https://github.com/cliffjohnson/todayimade. I need to get an open source license applied to this project, I think there might be a couple of different applications for it once it’s done, but that is another post.

Add A New Products Section to a Magento Store Homepage

Was looking for a way to add a New Products section to the homepage of a Magento store I’m working on a found a great write up on Richard Castera’s blog. All you really have to do is add this code to the homepage code in your CMS section:

{{block type="catalog/product_new" name="home.catalog.product.new" alias="product_homepage"template="catalog/product/new.phtml"}}

Check out the full blog post with some great back and forth and troubleshooting tips.

Once you have the new products displaying, this post on the Magento site will show you how to have more than five products displayed and how to add more than one row.

Could It Really Be That Easy?

In a project we are working on we needed a way to extract the number portion of a weight from a string. So we could receive any of the following:

21
21 lbs
21.3
21.3 lbs

We started looking into some regular expressions to do the job, but then ran across a page saying that you can just cast it to a float or int and it will drop the string bit automatically like so:

<?php
$string = “22.8 lbs”;
echo (float)$string;
?>

<?php
$string = “22.8 lbs”;
echo (float)$string;
?>

This should output 22.8. Not perfect for every situation, but pretty handy in the right one.