Search

Friends

Atomspheric CO2 (PPM)

Archives

Blather

Uptime verified by Wormly.com

21 October 2014

Codeship CI + Symfony 2 + PHPUnit

We've just moved from CircleCI (which was excellent) to Codeship, because we couldn't afford the Github fees any more. It definitely wasn't as easy as CircleCI, and the UI isn't as tidy. But Codeship works pretty well so far. The Setup Commands for a Symfony app go something like this...

phpenv local 5.4
export SYMFONY_ENV=test
mysql  -u $MYSQL_USER -p$MYSQL_PASSWORD -e "CREATE DATABASE test"
unzip -p app/Resources/Tests/test.sql.zip | mysql -u $MYSQL_USER -p$MYSQL_PASSWORD test
echo "xdebug.max_nesting_level = 250" >> $HOME/.phpenv/versions/5.4/etc/php.ini
echo "memory_limit = 512M" >> $HOME/.phpenv/versions/5.4/etc/php.ini
cp app/config/parameters.yml.dist app/config/parameters.yml
sed -i "s/database_user:.*/database_user: $MYSQL_USER/;s/database_password:.*/database_password: $MYSQL_PASSWORD/" app/config/parameters_test.yml

composer install --prefer-source --no-interaction
app/console doctrine:migrations:migrate --env=test --no-interaction

12 March 2013

Integrating Hero Framework accounts with Vanilla Forum using jsConnect

This is something of a hack, but it is pretty quick and easy. I've never used Smarty before, but it's pretty flexible (and slightly evil).

I put this in a Hero template called authenticate.thtml and mapped it to /authenticate. I installed the jsConnect module for Vanilla, set the secret and it was basically done. Seems to work for regular and embedded forums.

{strip}
{assign var=secret value='985d2f9eb57a8b55db3c04c20272bce9308764b0'}
{assign var=client_id value=$smarty.get.client_id}
{assign var=callback value=$smarty.get.callback}

{if $logged_in}
  {assign var=member value=['uniqueid'=>$member.id,'name'=>$member.first_name|cat:' '|cat:$member.last_name, 'email'=>$member.email, 'roles'=>'member']}
  {assign var=empty value=ksort($member)}

  {$member['signature'] = $member|@http_build_query|cat:$secret|@sha1}

  {$member['client_id'] = $client_id}
{else}
  {assign var=member value=['name'=>'', 'photourl'=>'']}
{/if}

{$callback}({$member|@json_encode})
{/strip}

25 June 2012

Slow performance hosting Symfony2 on cPanel/WHM

We've recently set up cPanel on VPS to host our big Symfony2 project. We were developing locally on a MAMP setup which was really fast. For production, we moved initially to a FastCGI shared host which was fairly fast as well. But to get PHP 5.3 we needed to make a few messy fiddles we weren't that happy and they didn't have APC. So we finally moved to a VPS so we could have PHP 5.3 with mod_php and whatever other guff we needed.

However, the system was incredibly slow. Between 50% and 30% of the speed of our local development server (which wasn't anything flash). We tried a bunch of combinations of memcache and APC configurations and then tried a few different Symfony2 options but nothing made much difference. In the end it turned out to be the open_basedir option that is normally on with cPanel accounts. This disables fstat caching, and Symfony2 does a LOT of fstat calls. Turning off open_basedir solved the issue and reduced page generation times from about 1500ms to 600ms. Which may not be an option for everyone.

See https://bugs.php.net/bug.php?id=52312.

22 March 2012

ExpressionEngine Logout Bug

ExpressionEngine has a pretty brittle session mechanism. It has all sorts of devices for making it more secure and harder to spoof. But it causes issues with quite a few of our clients. Today we found a weird problem with what turned out to be a proxy-related issue. Some requests would be be sent through the proxy and some weren't, so the IP address would change. Strangely, no one was ever logged out but some requests would fail (and be redirected back to the login screen with no message).

In system/expressionengine/libraries/Session.php ExpressionEngine includes a check for the IP address when it gets the session data. Commenting out the line for the IP address and turning off IP address checks in the configuration seems to have fixed it for me.

public function fetch_session_data()
{
    // Look for session.  Match the user's IP address and browser for added security.
    $this->EE->db->select('member_id, admin_sess, last_activity')
        ->where('session_id', (string) $this->sdata['session_id'])
        //->where('ip_address', $this->sdata['ip_address'])
        ->where('user_agent', $this->sdata['user_agent']);
...

14 December 2011

Preventing ordering out of stock items in Ubercart 3

In template.php or some such...

function site_uc_product_add_to_cart( $variables ) {
  $sku = $variables['form']['node']['#value']->model;
  $stocklevel = uc_stock_level($sku);
  if (is_numeric($stocklevel)) {
    // Stock tracking is active
    if ($stocklevel <= 0) {
      return '<div class="add-to-cart out-of-stock"><button disabled>' . t('Sold') . '</button></div>';
    }
    else {
      return theme_uc_product_add_to_cart($variables);
    }
  }
  else {
    // Stock tracking is not being used for this product, just show the add to cart button as normal
    return theme_uc_product_add_to_cart($variables);
  }
}

17 November 2011

Querying certain subclasses with Symfony2 & Doctrine2

We're using Symfony2's class table inheritance and I was trying to work out how to select only some subclasses using Doctrine2. It turned out to be pretty easy.

SELECT e FROM MyCustomBundle:ParentEntity e WHERE e NOT INSTANCE OF MyCustomBundle:ExcludedChildEntity

In the discriminator map in the super class you refer to the full qualified namespace and class name (\My\CustomBundle\Entity\ExcludedChildEntity) but in the DQL it works with Symfony2's shorthand.

$builder = $repository->createQueryBuilder('entity')
                      ->where('entity NOT INSTANCE OF MyCustomBundle:ParentEntity');

5 August 2008

Magic quotes and addslashes

I think I may have found a slightly nicer (and safer) solution than I've previously found to the problem of the PHP's magic_quotes_gpc. When you're converting old applications you don't want to just replace all the addslashes() with a conditional escaping method. Or just unquote all your form input on the assumption that the programmer was sensible. Your input won't necessarily come from forms or cookies, so that might reduce your security. You still want to escape everything that goes into the function, but maybe you want run stripslashes() on it first if you think it's probably GPC data and magic quoting is turned on.

<?php
function gpc_escape($str) {
    if(1 == get_magic_quotes_gpc()) {
        return mysql_escape_string(stripslashes($str));
    }
    else {
        return mysql_escape_string($str);
    }
}
?>

Then you can do something like:

$ find . -name *.php | xargs perl -pi -e 's/addslashes/gpc_escape/g'

16 June 2008

Apache again

I've finally ditched lighttpd + fastcgi and replaced it with Apache on smurf. Lighttpd was good, but fastcgi was a total dog. It broke all the time and it got to the point that I didn't want to host my friends sites anymore. Every time I went on holidays fastcgi seemed to fall over and all the sites would be down for a day or three.

So I've gone back to the stable world of Apache, although not on the important server. In all the years I used Apache and mod_php it gave me no problems at all. A total rock. I was seduced by lighty's memory footprint, but I was a fool.

I'll move the other server over to Apache as well at some point, the one with Thoughtful Foods and KSAsub.. I thought rewriting all the configuration files was going to be a pain, but it was actually really quick. RewriteCondition with -f is bloody marvellous.

16 August 2007

XCache with PHP5 and Lighttpd on Ubuntu Dapper

PHP is been pretty slow for me since I left Apache 2 and the PHP code caching behind. I tried turck mmcache with PHP4 and it worked pretty badly. It sped things up, but lighttpd started freezing up every few hours. It was probably FastCGI screwing up and it might have been fixed with FastCGI since then. But I'm all PHP5 now, so I needed to use something else. The Lighttpd guys suggested (and maybe created) XCache so I tried it. It only took a few minutes to install and it's working sweet. WordPress page loads are down from 300ms to 50ms. I just hope it doesn't screw other things up.

I used the XCache installation instructions but had to do things a bit differently.

  1. Downloaded the XCache source from http://xcache.lighttpd.net/

    ~/src $ wget http://... (the release url)
    ~/src $ tar -zxf xcache-*.tar.gz
    ~/src $ cd xcache
    
  2. You have to install php5-dev and make if you haven't got them

    ~/src $ sudo apt-get install php5-dev make
    
  3. Run the PHP/XCache installation stuff

    ~/src/xcache $ phpize
    ~/src/xcache $ ./configure --enable-xcache
    ~/src/xcache $ make
    ~/src/xcache $ sudo make install
    
  4. Edit the php.ini file to tell it where the xcache.so file is located. Mine was at /usr/lib/php5/20051025/xcache.so. You need to edit the xcache.size setting (I used 32M, but others use 64M) and the extension (or zend_extension) setting.

    ~/src/xcache $ find /usr -name xcache.so
    ~/src/xcache $ sudo vi /etc/php5/php.ini
    
  5. Check that it's working

    ~/src/xcache $ php-cgi -v
    
  6. Restart lighttpd

    ~/src/xcache $ sudo /etc/init.d/lighttpd restart
    

28 July 2007

Slices

Since moving this blog to SliceHost the page load time has dropped from over a second to 100-200ms. Sweet. I don't even have the cache turned on anymore.

25 April 2007

New Atomic Blogfeed

Blogfeed is now Atom-enabled. SimplePie is approximately four billion times better than PEAR fricking XML Feed Parser. And after a brief romance, I've concluded that PHP date() is much, much better than PEAR Date. If only PEAR wasn't so neatly integrated and standardised I'd abandon it altogether.

If anyone is wondering what all this means, it is that Tom, Steve and Anmol can now all come to the Blogfeed party.

22 April 2007

Drupal and the rest

I'd be inclined to support a worldwide ban on PHP content management systems that aren't called Drupal. Everything else is kind of shite.

17 March 2007

Blogfeed dates

Tom helpfully pointed out that Blogfeed dates were totally borked. I spent a fair while fixing them, and maybe I still haven't. Pear Date sure does suck arse. Timezones are awful horrid things. Quite a few people are an hour out still, but I'm pretty sure that's because they've put 10 in where 11 would have made a better timezone offset. Daylight saving is also a dog.

7 March 2007

Pleasant Fatalities in PHP4

I've often settled for rather ugly solutions to fatal errors in PHP pages. Without exceptions attempting to find your controller to output some error template always seemed messy. Occasionally I've settled for a die() although I never enjoy it.

Working on some tiny project for Denzil I wangled together this little fellow, which I'm quite happy with. Once your controller has started any PHP error anywhere will get routed through your fatalError() function. So you can put array index errors and that sort of thing into a nice template. If the error is in the template code then restore_error_handler() stops the script from looping around forever.

Another nice thing is that you can call trigger_error() from anywhere and you have a pleasant fatals-only exceptions mechanism. I really should have thought of this a long time ago.

class Controller {
    function Controller() {
        set_error_handler(array(&$this, 'handleError'));
    }

    function handleError($type, $string, $file, $line, $vars) {
        restore_error_handler();
        $this->fatalError("$string in $file at $line"); // or something
    }

    function fatalError($msg) {
        // output nice page with error msg
        exit;
    }
}

30 October 2006

WordPress Feed Plugin

I got sick of all the other WordPress RSS plugins, so I wrote another one. It doesn't use Magpie, because that's been pretty buggy for me. And it doesn't let you have different cache times for different feeds on the same page. This one uses PEAR, which I like more, but it's obviously a shame to throw in the whole of PEAR when WordPress has tried to avoid it. WordPress also stays away from classes, and plugins are kind of meant to, but configuring most RSS plugins is an arse.

I think I'm hoping that this will be easier for people to fiddle with than some of the others. I suspect that writing your own function for this could be easier than configuring the ones I've tried so far.

$feed = new Feed('http://del.icio.us/rss/');
$feed->limit(5);
$feed->lifetime(3600);
$feed->simple(); // Or $feed->extended()

There's a shortcut function to make things a bit neater.

feed($url, $limit, $lifetime, $extended);

You'll need XML_RSS and Cache_Lite. It doesn't support anything except RSS either.

wp-feeds.zip

11 October 2006

Code Igniter

Code Igniter is a really sweet MVC-ish framework. I've been spending my last week of sickness reading about all the PHP frameworks, and fiddling about with some of them. Seagull, Cake and Code Igniter seem to be the best.

Seagull is a bit of a mess, but seems to be built by more practical than average sorts of PHP coders. It has Flexy templates, and over the years I've come to like Flexy a lot. It's not the quickest template language to get productive with, but then none of them really are.

Cake is pretty closely modelled on Rails, and is good.

But my favourite was Code Igniter, even though it doesn't have models in a proper sense. But it's really sensibly designed so it's easy to extend. I find with most frameworks, if you don't do what you're told by the tutorials and manuals, you won't get very far. It's also really light and fast, unlike PEAR-based frameworks, and probably Rails.

But I'm more convinced than ever that Ruby (probably with Rails in tag) are going to take over the world. The only real argument I've heard for using a PHP framework is that not all hosting providers do Rails. Which doesn't bode well for PHP. Who knows how long it's embeddedness advantage will last.

1 September 2006

Gcal API and PHP

Using the PEAR XML Parser I was able to make a nifty interface to Google Calendar for the Food Coop Roster in about 40 minutes. It uses the Google Calendar API. The built-in syndication stuff Google gives you is pretty average. I even made it a Drupally sort of module. Although at the moment it doesn't do anything very spectacular.

19 June 2006

Vanilla Forum

Vanilla is a really nice piece of software, in a field utterly dominated by appalling, bloated, insecure, user-unfriendly crap. Vanilla might not be any more secure than the others, but it's far better in all other regards.

10 June 2006

PHP and Ruby

I predict that PHP will go, and Ruby will replace it. For a developer, the only reason to keep using PHP is its transportability. And that advantage will disappear as web hosts realise that PHP only has this advantage going for it and start installing Ruby. I've been looking at the PHP MVC "frameworks", and they're OK, but you wouldn't use them unless you were wedded to PHP. There is nothing in them that people couldn't have developed five years ago. Even if they had, it still wouldn't have saved PHP. Ruby has elegance that PHP seems proud not to have.

5 June 2006

Secure Forum

I've been tempted to write a secure PHP bulletin board. One currently doesn't exist. The ones that do are ultra-insecure and generally suck. There needs to be one with a proper templating language, so templates don't have PHP code in them. They need to have some better database abstraction, to reduce security bugs. How hard can it be to build a secure system? I reckon they just need to think a bit harder about the design. Which probably means starting from scratch.

0.650 seconds