mcdruid.co.uk - drupal-planet http://mcdruid.co.uk.php53/taxonomy/term/45/0 en How to cleanly delete a Drupal file with drush http://mcdruid.co.uk.php53/content/how-to-cleanly-delete-a-drupal-file-with-drush <p>This is a simple trick which (unless my googlefu simply failed me) I didn't find described anywhere when I had a quick look:</p> <p><div class="geshifilter"><pre class="bash geshifilter-bash" style="font-family:monospace;">$ drush ev <span style="color: #ff0000;">'$file = file_load(21749); var_dump(file_delete($file, TRUE));'</span> bool<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">true</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></p> <p>This means all the appropriate hooks are called in <a href="https://api.drupal.org/api/drupal/includes%21file.inc/function/file_delete/7" rel="nofollow">file_delete</a> so the Drupal API gods should smile on you, and you should get to see the TRUE/FALSE result reflecting success or otherwise. Note that we're passing $force=TRUE "indicating that the file should be deleted even if the file is reported as in use by the file_usage table." So be careful.</p> <p>To delete multiple files you could use <a href="https://api.drupal.org/api/drupal/includes%21file.inc/function/file_load_multiple/7" rel="nofollow">file_load_multiple</a> but there's not a corresponding file_delete_multiple function, so you'd have to loop over the array of file objects.</p> <p>That's all there is to this one.</p> drupal drupal-planet drush Wed, 08 Oct 2014 14:43:09 +0000 drew 39 at http://mcdruid.co.uk.php53 Check your cache before you wreck yourself http://mcdruid.co.uk.php53/content/check-your-cache-before-you-wreck-yourself <p>Cache invalidation is known as one of the very few <em>hard things in computer science</em>.</p> <p>It seems to be a common misconception that Drupal's cache_get checks whether a given cache entry has expired, and won't return a stale result. In fact, in Drupal this is not always the case.</p> <p>The docs for both D6 and D7 actually say that if a specific timestamp is given as the $expire parameter in a cache_set, that this <em>"Indicates that the item should be kept at least until the given time, after which it behaves like CACHE_TEMPORARY."</em>. [<a href="https://api.drupal.org/api/drupal/includes!cache.inc/function/cache_set/6" rel="nofollow">D6</a>/<a href="https://api.drupal.org/api/drupal/includes!cache.inc/function/cache_set/7" rel="nofollow">D7</a>]</p> <p>So this does not say that cache entries will expire (i.e. cache_get will not return them) after this timestamp has passed; rather it says that "the item should be removed at the next general cache wipe."</p> <p>What this actually means is that it's the responsibility of the code which does a cache_get to check whether any object that it gets back is still valid in terms of the time it should expire.</p> <p>So, if you want to use Drupal's cache system in D6 or D7 to store a value for a short amount of time, but not wait for the cache entry to be cleared until "the next general cache wipe", you must check the expire timestamp on any cache object that you receive back from a cache_get.</p> <p>Here's a little php script which illustrates this; we still get a cache object back even although it has expired:</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> &nbsp; <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'TEST_CACHE_LIFETIME'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// seconds</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><a href="http://www.php.net/defined"><span style="color: #990000;">defined</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'REQUEST_TIME'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// REQUEST_TIME is in D7 but not D6</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'REQUEST_TIME'</span><span style="color: #339933;">,</span> <a href="http://www.php.net/time"><span style="color: #990000;">time</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">print</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>###<span style="color: #000099; font-weight: bold;">\n</span>running cache test at &quot;</span> <span style="color: #339933;">.</span> REQUEST_TIME <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$reset_cache</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cached</span> <span style="color: #339933;">=</span> cache_get<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'test_cache_expiry'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'cache'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">print</span> <span style="color: #0000ff;">'this came from cache: '</span> <span style="color: #339933;">.</span> <a href="http://www.php.net/print_r"><span style="color: #990000;">print_r</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cached</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$cached</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">expire</span> <span style="color: #339933;">&lt;</span> REQUEST_TIME<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$reset_cache</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">print</span> <span style="color: #0000ff;">&quot;cached data has expired; resetting<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$reset_cache</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$reset_cache</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">print</span> <span style="color: #0000ff;">'setting this to cache: '</span> <span style="color: #339933;">.</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/md5"><span style="color: #990000;">md5</span></a><span style="color: #009900;">&#40;</span><a href="http://www.php.net/rand"><span style="color: #990000;">rand</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> cache_set<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'test_cache_expiry'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'cache'</span><span style="color: #339933;">,</span> REQUEST_TIME <span style="color: #339933;">+</span> TEST_CACHE_LIFETIME<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p>...and here's what happens if we run it a few times in quick succession:</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">$ for i in {1..8}; do drush scr cache_test.php; sleep 3; done &nbsp; ### running cache test at 1384557409 setting this to cache: 5d9f014b374764e35220ead02102b1e7 &nbsp; ### running cache test at 1384557412 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; 5d9f014b374764e35220ead02102b1e7 [created] =&gt; 1384557409 [expire] =&gt; 1384557419 [serialized] =&gt; 0 ) &nbsp; ### running cache test at 1384557416 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; 5d9f014b374764e35220ead02102b1e7 [created] =&gt; 1384557409 [expire] =&gt; 1384557419 [serialized] =&gt; 0 ) &nbsp; ### running cache test at 1384557419 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; 5d9f014b374764e35220ead02102b1e7 [created] =&gt; 1384557409 [expire] =&gt; 1384557419 [serialized] =&gt; 0 ) &nbsp; ### running cache test at 1384557422 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; 5d9f014b374764e35220ead02102b1e7 [created] =&gt; 1384557409 [expire] =&gt; 1384557419 [serialized] =&gt; 0 ) cached data has expired; resetting setting this to cache: a57b9e9734824207e0aa6d4d6a4b6973 &nbsp; ### running cache test at 1384557426 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; a57b9e9734824207e0aa6d4d6a4b6973 [created] =&gt; 1384557422 [expire] =&gt; 1384557432 [serialized] =&gt; 0 ) &nbsp; ### running cache test at 1384557429 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; a57b9e9734824207e0aa6d4d6a4b6973 [created] =&gt; 1384557422 [expire] =&gt; 1384557432 [serialized] =&gt; 0 ) &nbsp; ### running cache test at 1384557433 this came from cache: stdClass Object ( [cid] =&gt; test_cache_expiry [data] =&gt; a57b9e9734824207e0aa6d4d6a4b6973 [created] =&gt; 1384557422 [expire] =&gt; 1384557432 [serialized] =&gt; 0 ) cached data has expired; resetting setting this to cache: abbe82035a1bcaea187259f316f04309</pre></div></p> <p>Note that not all cache backends work the same - memcache doesn't seem to return cache entries after their expire timestamp has passed, for example.</p> <p>We should assume, however, that we might well get a cache object which has expired back from cache_get, so we should always check the expire property before assuming that the cache entry is valid</p> <p>See <a href="https://drupal.org/node/534092" title="https://drupal.org/node/534092" rel="nofollow">https://drupal.org/node/534092</a> for some discussion as to whether this is a bug or a feature.</p> cache drupal-planet Fri, 15 Nov 2013 23:37:03 +0000 drew 37 at http://mcdruid.co.uk.php53 git commit author - give credit where credit is due http://mcdruid.co.uk.php53/content/git-commit-author-give-credit-where-credit-is-due <p> Quite some time ago I wrote a post about how <a href="http://www.mcdruid.co.uk/content/patching-makes-you-feel-good" rel="nofollow">patching makes you feel good</a> in which I talked about the motivations for, and benefits of submitting patches on drupal.org (d.o). I concluded by suggesting that project maintainers should be generous in recognising the efforts of those who submit patches. </p> <p> Well, now that d.o has its magnificent git infrastructure, project maintainers have even better tools for giving credit to contributors who help fix or improve the code. There is still the well-established <a href="http://drupal.org/node/52287" rel="nofollow">convention for commit messages</a> which encourages that "others [who] have contributed to the change you are committing" are credited by name. e.g. </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">Issue #123456 by dww, Dries: Added project release tracking.</pre></div></p> <p> Similar messages are often added to the project's changelog too. </p> <p> The new tool that perhaps not everyone knows about yet is the ability to <a href="http://drupal.org/node/1146430" rel="nofollow">assign the authorship of the commit to another user</a> e.g. </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">git commit --author=[username]@[uid].no-reply.drupal.org</pre></div></p> <p> This is appropriate when committing a patch that is entirely somebody else's work. Perhaps some maintainers will be generous and attribute authorship even if they've had to make a few tweaks to the patch, but somebody else did the majority of the work to identify and fix a bug, for example. </p> <p> When a user is credited as the author in this way, the commit will show up on their drupal.org profile page, which I think many people will feel is a great reward for the time they spent putting a patch together. </p> <p> There are however some limitations and drawbacks to the system. The committer of the patch is not <em>rewarded</em> by seeing their commit count incremented, which some may find a disincentive for generosity in attributing authorship. </p> <p> Where the maintainer might split the credit in a commit message for a fix where a user was helpful by giving a detailed bug report in the issue queue, but where they themselves had to actually fix the problem, for example, they're probably justified in leaving themselves as the author of the commit. Of course they can still mention the helpful user in the commit message and changelog. </p> <p> There will surely also be less monochrome cases where authorship of the code being committed should be split between multiple users. As far as I'm aware, the git infrastructure on d.o doesn't cater for this situation, and messy workarounds such as breaking the commit up to split authorship have been suggested. </p> <p> There are undoubtedly some limitations, and project maintainers will occasionally find themselves with tricky decisions to make. However, for the reasons I detailed in my <em>patching makes you feel good</em> post, I really encourage maintainers to be generous with the credit when it comes to patches which have been submitted in issue queues, and the option to set an author for a commit in git is a great way of doing so. </p> drupal drupal-planet drupal.org git Tue, 07 Feb 2012 23:14:58 +0000 drew 36 at http://mcdruid.co.uk.php53 default Drupal contexts like default views http://mcdruid.co.uk.php53/content/default-drupal-contexts-like-default-views <p> I was using the brilliant <a href="http://drupal.org/project/context" rel="nofollow">context</a> module in a project recently. The fact that it uses <a href="http://drupal.org/project/ctools" rel="nofollow">ctools</a> means it has a few characteristics reminiscent of <a href="http://drupal.org/project/views" rel="nofollow">views</a> (and <a href="http://drupal.org/project/panels" rel="nofollow">panels</a>). One of these is the import / export functionality, and the distinction between the different types of <em>storage</em> for the contexts you've set up - i.e. </p> <ul> <li>normal</li> <li>default</li> <li>overridden</li> </ul> <p> Seeing this, I was certain there must be a way of defining contexts in code in a module, similar to the way you can define default views hook_views_api() and hook_views_default_views(). However, I really struggled to find any documentation about the correct hooks and syntax to achieve this. </p> <p> Of course, one way of finding out was to use the <a href="http://drupal.org/project/features" rel="nofollow">features</a> module to package up a <em>context</em> and have a look at the code it produced. </p> <p> It turns out this works in a very similar way to the views module (unsurprisingly given their shared heritage). I thought I'd document it here in case other people are struggling to find some clear instructions as to how to include your own default context objects in your module. </p> <p> Just like with views, you need to implement an api hook, and then the actual context_default_contexts hook which returns the exported context object(s):</p> <p> <div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/** * Implementation of hook_ctools_plugin_api(). */</span> <span style="color: #000000; font-weight: bold;">function</span> mymodule_ctools_plugin_api<span style="color: #009900;">&#40;</span><span style="color: #000088;">$module</span><span style="color: #339933;">,</span> <span style="color: #000088;">$api</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$module</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">&quot;context&quot;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$api</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">&quot;context&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">return</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;version&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p>and then in mymodule.context.inc something along the lines of this:</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/** * Implementation of hook_context_default_contexts(). */</span> <span style="color: #000000; font-weight: bold;">function</span> mymodule_context_default_contexts<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$export</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> stdClass<span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">disabled</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">/* Edit this to true to make a default context disabled initially */</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">api_version</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'testy'</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">description</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'testing context'</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tag</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">conditions</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'node'</span> <span style="color: #339933;">=&gt;</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'values'</span> <span style="color: #339933;">=&gt;</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'page'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'page'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'options'</span> <span style="color: #339933;">=&gt;</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'node_form'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'1'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">reactions</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'menu'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'admin/help'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">condition_mode</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">// Translatables</span> <span style="color: #666666; font-style: italic;">// Included for use with string extractors like potx.</span> t<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'testing context'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$export</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$context</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$context</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$export</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p> Perhaps the reason I couldn't find easy documentation for this is that it's really the ctools api doing the work - I think I'll submit an issue for the context module though to suggest at least a hint is added to the README to point developers in the right direction.<br /> [edit]I posted a <a href="http://drupal.org/node/1093002" rel="nofollow">documentation issue</a> on drupal.org[/edit]</p> <p> One of the posts I did find which helped was <a href="http://stellapower.net/content/using-chaos-tools-module-create-exportables" rel="nofollow">Stella Power's interesting write up on how to use ctools to create exportables in your own module</a>.</p> context ctools drupal drupal-planet Mon, 14 Mar 2011 19:36:38 +0000 drew 34 at http://mcdruid.co.uk.php53 using Geany as an editor for Drupal development http://mcdruid.co.uk.php53/content/using-geany-as-an-editor-for-drupal-development <div class="field field-type-filefield field-field-image"> <div class="field-items"> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/drupal_api_argument_list.png" alt="Drupal API function argument list" title="" width="150" height="76" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/drupal_autocomplete.png" alt="Drupal API function name auto-completion" title="" width="150" height="76" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> </div> </div> <p> In general I'm a happy vim user, but now and again I am asked why I'm using such an antiquated environment. Editor preference is of course a topic over which many long and pointless arguments have been waged - often from intractable dug-in positions of dogma. I think it's good to poke your head above the trench occasionally and see what else is available. </p> <p> I suppose the other end of the spectrum to something as lightweight (albeit extensible) as vim is a full IDE such as Eclipse. There are undoubtedly many great things about the Eclipse environment, but I just can't get over the annoyance of my rhythm being interrupted as I type; it feels like it's just trying to do too much for me. </p> <p> It was in this spirit that I recently gave <a href="http://www.geany.org" rel="nofollow">Geany</a> a try. It's a lightweight cross-platform editor based on GTK, with some basic IDE features. </p> <p> As a Drupal developer one of the first pleasant surprises was that I didn't need to tell it to treat .module and .install files as PHP scripts - it's smart enough to see the opening <em>&lt;?php</em> tag and give me syntax highlighting etc... straight away. </p> <p> It does a few simple things which make life easier - code folding if you want, a list of functions in the current file, and the facility to jump to the definition of a given function or constant, or search for the usage of whatever your cursor is over within the current document, or all open documents. It also does simple code completion, auto indentation, and has a tag library of PHP's built in functions. For PHP files, the <em>compile</em> button checks the syntax of the current file using <em>php -l</em> which is particularly useful when working on install or update hooks in Drupal. </p> <p> Working with Drupal we're often not using built-in PHP functions, but rather those from the Drupal API. It's possible to get some help from Geany here too. Whilst I've seen this done with Eclipse and other IDEs before, this is one of the areas where they can become very cumbersome - for example as they try to re-index a few mb of source files for the project in the background while you're typing. The approach I'm trying out with Geany is more along the lines of <a href="http://openflows.com/blog/mvc/2009/01/27/using-exuberant-ctags-drupal" rel="nofollow">using ctags with vim</a> (or emacs). </p> <p> The idea is to scan through the source code of the project (Drupal core in this case) just once, and make a list of all the function names (and constants if you like) with a few helpful details such as the argument lists. Rather annoyingly <a href="http://www.geany.org/manual/current/#global-tags-file-format" rel="nofollow">Geany uses the slightly obscure tagmanager format for its tags</a>. The docs suggest that you can use Geany itself to generate your list of tags: </p> <p> So, inside a freshly drushed copy of Drupal6 core, I tried </p> <p><div class="geshifilter"><pre class="bash geshifilter-bash" style="font-family:monospace;">geany <span style="color: #660033;">-g</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>drupal6.php.tags $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">find</span> . <span style="color: #660033;">-type</span> f <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*.php'</span> <span style="color: #660033;">-o</span> <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*.module'</span> <span style="color: #660033;">-o</span> <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*.inc'</span> <span style="color: #660033;">-o</span> <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*.install'</span> <span style="color: #660033;">-o</span> <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*.engine'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></p> <p> ...(using the unix find command to provide geany with a list of all the files with the common file extensions Drupal uses for PHP files). </p> <p> This produced a file in tagmanager format, which geany was happy to use. This gave me auto-completion for Drupal function names, but it was missing a very useful feature - the argument list (which are provided for PHP's built-in functions). </p> <p> Luckily Geany supports an alternative tag format - pipe-delimited - which is easier to manipulate than the tagmanager format. There is a <a href="http://download.geany.org/contrib/tags/drupal.php.tags" rel="nofollow">contributed tags file available for Drupal</a> which includes basic argument lists, but from the timestamp on the file I think this is probably for Drupal 5. </p> <p> So how about rolling our own? Looking at the tags file which exuberent ctags produces for Drupal core, and at what we need to provide in the basic pipe-delimited tags file, ctags does most of the work for us. </p> <h4>ctags output</h4> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">drupal_set_message includes/bootstrap.inc /^function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {$/ drupal_set_title includes/path.inc /^function drupal_set_title($title = NULL) {$/</pre></div></p> <h4>geany pipe-delimited format</h4> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">function_name|return_type|argument, list|</pre></div></p> <p> I'm sure someone could come up with an awk one-liner to do this, but I resorted to a quick php cli script. </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$lines</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/file"><span style="color: #990000;">file</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'tags'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$lines</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$line</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/preg_match_all"><span style="color: #990000;">preg_match_all</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'[function (.*)\((.*)\) ]U'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$line</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">print</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'||'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;|<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p> Unfortunately ctags is not clever enough to give us the return type, which might be there in doxygen-style comments (as will better info about the arguments), but this gives us: </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">drupal_set_message||$message = NULL, $type = 'status', $repeat = TRUE| drupal_set_title||$title = NULL|</pre></div></p> <p> ...which is pretty useful as a quick reminder. </p> <p> With the addition of the Drupal tags file, I'm finding Geany a really good compromise between the light-weight speed of something like vim whilst offering some really useful IDE-type features for Drupal development. Why not help yourself to the tags file and give it a go. </p> <p> [edit]<br /> added after some comments and feedback on IRC:<br /> You can enable the tag files (it only really makes sense to use one of them at a time) by placing them in:<br /> <code><br /> ~/.config/geany/tags<br /> </code><br /> ...you will also have to rename the files to remove the underscore, as otherwise geany will refuse to use them. </p> <p> If you have any problems, try launching geany from the commandline with the -v ( --verbose) option.<br /> [/edit] </p> <table id="attachments" class="sticky-enabled"> <thead><tr><th>Attachment</th><th>Size</th> </tr></thead> <tbody> <tr class="odd"><td><a href="/sites/mcdruid.co.uk/files/drupal6.php_.tags">drupal6.php_.tags</a></td><td>75.68 KB</td> </tr> <tr class="even"><td><a href="/sites/mcdruid.co.uk/files/drupal7.php_.tags">drupal7.php_.tags</a></td><td>185.38 KB</td> </tr> </tbody> </table> ctags drupal drupal-planet editor ide Tue, 08 Feb 2011 19:41:18 +0000 drew 33 at http://mcdruid.co.uk.php53 how to increase php memory limit for drush without access to php.ini http://mcdruid.co.uk.php53/content/how-to-increase-php-memory-limit-for-drush-without-access-to-phpini <p>I recently found myself trying to use drush to set up a Drupal 6 install on a server where I did not have root access. I kept getting errors along the lines of this: </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 1234 bytes)</pre></div></p> <p> I didn't have permission to edit the php.ini file for php_cli, so I had to find another workaround. The solution's pretty simple and comes courtesy of the <em>drushrc.php</em> file. </p> <p> drush looks in a list of locations for a config file, and the example.drush.php which you'll find inside includes in your drush directory contains the following instructions: </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"> * Rename this file to drushrc.php and optionally copy it to one of * five convenient places, listed below in order of precedence: * * 1. Drupal site folder (e.g sites/{default|example.com}/drushrc.php). * 2. Drupal installation root. * 3. In any location, as specified by the --config (-c) option. * 4. User's .drush folder (i.e. ~/.drush/drushrc.php). * 5. System wide configuration folder (e.g. /etc/drush/drushrc.php). * 6. Drush installation folder.</pre></div></p> <p> I simply followed these instructions (going for ~/.drush/drushrc.php in this case), and added the following line to the end of the file: </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><a href="http://www.php.net/ini_set"><span style="color: #990000;">ini_set</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'memory_limit'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'128M'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></p> <p> You can check that this is getting picked up like so: </p> <p><div class="geshifilter"><pre class="bash geshifilter-bash" style="font-family:monospace;">drush php-eval <span style="color: #ff0000;">'print ini_get(&quot;memory_limit&quot;)'</span> ; 128M</pre></div></p> <p> ...and the real proof of the pudding is that I'm no longer getting the memory exhausted error messages. </p> drupal drupal-planet drush memory php php_cli Sun, 28 Nov 2010 23:56:22 +0000 drew 31 at http://mcdruid.co.uk.php53 simple twitter feed on Drupal 5 http://mcdruid.co.uk.php53/content/simple-twitter-feed-on-drupal-5 <p> I was recently asked to add a simple twitter feed to a Drupal 5 site I built a few years ago. You know the sort of thing - a block in the sidebar with the 5 most recent tweets from the organisation's twitter account. Unfortunately, this turned out to be one of those requests that sounds like it's going to be really easy, but is not (especially on Drupal 5). I came up with a solution which does the job quite nicely, but it's a bit of a hack; I wouldn't do it like this on a new site - but then of course I wouldn't be using Drupal 5. </p> <p> There are several twitter modules for Drupal, as you'd expect. The <a href="http://drupal.org/project/twitter" rel="nofollow">twitter module</a> does have a Drupal 5 version, but it's a minimal dev release and doesn't seem to offer much of the functionality of the other releases. The other module which sounded promising was <a href="http://drupal.org/project/twitter_pull" rel="nofollow">twitter pull</a> but this has no D5 release at all. I had a think about doing a backport, but this was supposed to be a quick favour and with the imminent release of D7 (ahem!), working on Drupal 5 code hardly seems like an investment in the future. </p> <p> Then I checked, and found that twitter provides RSS feeds for users' timelines, and obviously D5 has a perfectly functional RSS aggregator module built-in. The RSS feed looks something like this: </p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">http://twitter.com/statuses/user_timeline/30355784.rss</pre></div></p> <p> ...so I set this up as a feed (admin/content/aggregator), and this automatically provided a block. This works okay, but the problem is that each item ends up like this:</p> <p> <div class="geshifilter"><pre class="html4strict geshifilter-html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://twitter.com/mcdruid_co_uk/statuses/26748027524&quot;</span>&gt;</span>mcdruid_co_uk: Drupal Quiz module: &quot;action to be preformed after a user has completed Quiz: Ban IP address of current user&quot; - seems a bit extreme, shirley?<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span></pre></div></p> <p> ...so we end up with the entire tweet being a link, pointing at a page displaying just that one tweet. This is not exactly what I was hoping for. </p> <p> So here's the slightly nasty hack; like all well-written Drupal modules, aggregator runs its output through a <a href="http://api.drupal.org/api/function/theme_aggregator_block_item/5" rel="nofollow">theme function</a>, which can be overridden: </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000000; font-weight: bold;">function</span> theme_aggregator_block_item<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">,</span> <span style="color: #000088;">$feed</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">uid</span> <span style="color: #339933;">&amp;&amp;</span> module_exists<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> user_access<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'edit own blog'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> theme<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'image'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'misc/blog.png'</span><span style="color: #339933;">,</span> t<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog it'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> t<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog it'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$output</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'&lt;div class=&quot;icon&quot;&gt;'</span><span style="color: #339933;">.</span> l<span style="color: #009900;">&#40;</span><span style="color: #000088;">$image</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'node/add/blog'</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'title'</span> <span style="color: #339933;">=&gt;</span> t<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Comment on this news item in your personal blog.'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'class'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'blog-it'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;iid=<span style="color: #006699; font-weight: bold;">$item-&gt;iid</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;/div&gt;'</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #666666; font-style: italic;">// Display the external link to the item.</span> <span style="color: #000088;">$output</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'&lt;a href=&quot;'</span><span style="color: #339933;">.</span> check_url<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><a href="http://www.php.net/link"><span style="color: #990000;">link</span></a><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;'</span><span style="color: #339933;">.</span> check_plain<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;/a&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$output</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></p> <p> We wouldn't necessarily want to mess with the output of feeds other than this twitter one, so we need a way of identifying items from this feed. I noticed that twitter's RSS feed prepends the twitter username to each post, so we can use this to identify them. </p> <p> I borrowed a function from the twitter module which deals with twitter <em>@usernames</em> and <em>#hashtags</em>. After that, running the tweet through the default input filter strips out potential nasties, and also converts URLs to links (assuming you have this switched on in your default input filter). The item includes a timestamp, so I used that to append a date/time. I didn't want the <em>blog it</em> stuff, so my theme code (in template.php) ended up looking like this: </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ORGNAME_TWITTER_USERNAME'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'orgname'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * theme aggregator items */</span> <span style="color: #000000; font-weight: bold;">function</span> mytheme_aggregator_block_item<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">,</span> <span style="color: #000088;">$feed</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// horrible hack, but catch items which are part of the twitter feed</span> <span style="color: #000088;">$twitter_username</span> <span style="color: #339933;">=</span> variable_get<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'orgname_twitter_username'</span><span style="color: #339933;">,</span> ORGNAME_TWITTER_USERNAME<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$tweet_prefix</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$twitter_username</span>: &quot;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/strpos"><span style="color: #990000;">strpos</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tweet_prefix</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// chop the username part from the start</span> <span style="color: #000088;">$tweet</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/substr"><span style="color: #990000;">substr</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #339933;">,</span> <a href="http://www.php.net/strlen"><span style="color: #990000;">strlen</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet_prefix</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// @usernames</span> <span style="color: #000088;">$tweet</span> <span style="color: #339933;">=</span> _mytheme_twitter_link_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// #hashtags</span> <span style="color: #000088;">$tweet</span> <span style="color: #339933;">=</span> _mytheme_twitter_link_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'#'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'http://search.twitter.com/search?q=%23'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// add date</span> <span style="color: #000088;">$tweet</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">' &lt;span class=&quot;date&quot;&gt;('</span> <span style="color: #339933;">.</span> format_date<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">timestamp</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">')&lt;/span&gt;'</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// filter</span> <span style="color: #000088;">$tweet</span> <span style="color: #339933;">=</span> check_markup<span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$output</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/trim"><span style="color: #990000;">trim</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tweet</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// default implementation</span> <span style="color: #000088;">$output</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;a href=&quot;'</span><span style="color: #339933;">.</span> check_url<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><a href="http://www.php.net/link"><span style="color: #990000;">link</span></a><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;'</span><span style="color: #339933;">.</span> check_plain<span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;/a&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$output</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * stolen from twitter module (for D6) * * This helper function converts Twitter-style @usernames and #hashtags into * actual links. */</span> <span style="color: #000000; font-weight: bold;">function</span> _mytheme_twitter_link_filter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'@'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$destination</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://twitter.com/'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$matches</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/\&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'([a-z0-9_]{0,15})/i'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/^'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'([a-z0-9_]{0,15})/i'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/(\s+)'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'([a-z0-9_]{0,15})/i'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$replacements</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'&gt;&lt;a href=&quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$destination</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${1}&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${1}&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;a href=&quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$destination</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${1}&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${1}&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'${1}&lt;a href=&quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$destination</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${2}&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$prefix</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'${2}&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <a href="http://www.php.net/preg_replace"><span style="color: #990000;">preg_replace</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #339933;">,</span> <span style="color: #000088;">$replacements</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p> The result is nicely filtered and formatted tweets, with <em>@usernames</em>, <em>#hashtags</em> and URLs all converted to links. </p> <p> If you don't like the way the aggregator module provides the block for the feed, you can always take what aggregator outputs and manipulate it with your own module code, e.g.: </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"> <span style="color: #666666; font-style: italic;">// get the block content from aggregator module</span> <span style="color: #000088;">$block</span> <span style="color: #339933;">=</span> module_invoke<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'aggregator'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'block'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'view'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'feed-1'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$block_content</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$block</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'content'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></div> </p> <p> It'll do the job until the site's upgraded to a newer version of Drupal. </p> drupal drupal-planet drupal5 rss twitter Fri, 08 Oct 2010 22:25:41 +0000 drew 30 at http://mcdruid.co.uk.php53 themeing validation errors for checkboxes in drupal http://mcdruid.co.uk.php53/content/themeing-validation-errors-for-checkboxes-in-drupal <div class="field field-type-filefield field-field-image"> <div class="field-items"> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/firefox_3_no_span.png" alt="Firefox 3 no span" title="Firefox 3 no span" width="150" height="80" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/firefox_3_with_span.png" alt="Firefox 3 with span" title="Firefox 3 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/chrome_6_no_span_0.png" alt="Chrome 6 no span" title="Chrome 6 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/chrome_6_with_span.png" alt="Chrome 6 with span" title="Chrome 6 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_6_no_span.png" alt="IE6 no span" title="IE6 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_6_with_span_0.png" alt="IE6 with span" title="IE6 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_7_no_span.png" alt="IE7 no span" title="IE7 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_7_with_span.png" alt="IE 7 with span" title="IE 7 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_8_no_span.png" alt="IE 8 no span" title="IE 8 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/ie_8_with_span.png" alt="IE8 with span" title="IE8 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/opera_10_no_span.png" alt="Opera 10 no span" title="Opera 10 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/opera_10_with_span.png" alt="Opera 10 with span" title="Opera 10 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/win_safari_5_no_span.png" alt="(Win) Safari 5 no span" title="(Win) Safari 5 no span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/win_safari_5_with_span.png" alt="(Win) Safari 5 with span" title="(Win) Safari 5 with span" width="150" height="55" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> </div> </div> <p> I came across a problem when working on a Drupal user registration form which had to include an <em>accept terms and conditions</em> checkbox. In fact, I came across a couple of problems, but I only had to fix one myself. </p> <p> At present there are some bugs in Drupal 6 core pertaining to mandatory checkboxes. Luckily, <em><a href="http://drupal.org/project/checkbox_validate" rel="nofollow">there's a module for that</a></em>. I was using the handy <a href="http://drupal.org/project/terms_of_use" rel="nofollow">terms of use</a> module, which works around the mandatory checkbox problems with or without the help of the checkbox_validate module. </p> <p> One problem remained though - if I submitted the registration form without ticking the mandatory <em>terms of use</em> checkbox, the form validation worked in that it stopped me proceeding, and I saw the <em>You must agree with the Terms of Use to get an account</em> error message at the top of the form, but there was no visual highlighting of the checkbox in question. </p> <p> A poke around with firebug confirmed that the form API has been cajoled into doing its <a href="http://api.drupal.org/api/function/form_set_error/6" rel="nofollow">form_set_error</a> thing, and the checkbox had the <em>error</em> class. However, styling form elements - particularly the different types of inputs - with CSS has <a href="http://www.456bereastreet.com/lab/form_controls/checkboxes/" title="(slightly old) examples of inconsistent rendering of CSS-styled checkboxes in different browsers" rel="nofollow">always been a bit hit-and-miss</a>. The 2px solid red border that the stylesheets specified should be around the checkbox was nowhere to be seen. </p> <p> I checked in several other browsers (lots of screenshots included with this post) - it looked like the IEs and Opera were the only browsers which rendered the red border around the checkbox - Firefox, Chrome and Safari did not. </p> <p> My workaround is to override the <a href="http://api.drupal.org/api/function/theme_checkbox/6" rel="nofollow">theme function for a checkbox</a>, and to wrap checkboxes with the 'error' class in a span which I can then style. In my CSS I also turn off the red border for the checkbox itself, as otherwise you get double borders in the browsers which don't have this problem in the first place: </p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000000; font-weight: bold;">function</span> mytheme_checkbox<span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> _form_set_class<span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form-checkbox'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;input '</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'type=&quot;checkbox&quot; '</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'name=&quot;'</span><span style="color: #339933;">.</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; '</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'id=&quot;'</span><span style="color: #339933;">.</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#id'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; '</span> <span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'value=&quot;'</span><span style="color: #339933;">.</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#return_value'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot; '</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#value'</span><span style="color: #009900;">&#93;</span> ? <span style="color: #0000ff;">' checked=&quot;checked&quot; '</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> drupal_attributes<span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#attributes'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">' /&gt;'</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/strpos"><span style="color: #990000;">strpos</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#attributes'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'class'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'error'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&lt;span class='checkbox-error'&gt;<span style="color: #006699; font-weight: bold;">$checkbox</span>&lt;/span&gt;&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><a href="http://www.php.net/is_null"><span style="color: #990000;">is_null</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#title'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'&lt;label class=&quot;option&quot; for=&quot;'</span><span style="color: #339933;">.</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#id'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;'</span><span style="color: #339933;">.</span> <span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">' '</span><span style="color: #339933;">.</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#title'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;/label&gt;'</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$element</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'#title'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> theme<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form_element'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$element</span><span style="color: #339933;">,</span> <span style="color: #000088;">$checkbox</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p>...and...</p> <p><div class="geshifilter"><pre class="css geshifilter-css" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/* CSS */</span> <span style="color: #6666ff;">.checkbox-error</span> <span style="color: #00AA00;">&#123;</span> <span style="color: #000000; font-weight: bold;">border</span><span style="color: #00AA00;">:</span> <span style="color: #933;">2px</span> <span style="color: #993333;">solid</span> <span style="color: #993333;">red</span><span style="color: #00AA00;">;</span> <span style="color: #00AA00;">&#125;</span> <span style="color: #6666ff;">.form-item</span> <span style="color: #6666ff;">.checkbox-error</span> input<span style="color: #6666ff;">.error</span> <span style="color: #00AA00;">&#123;</span> <span style="color: #000000; font-weight: bold;">border</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span><span style="color: #00AA00;">;</span> <span style="color: #00AA00;">&#125;</span></pre></div></p> <p> The results are not visually perfect - the red border on my span doesn't always hug the edges of the checkbox very neatly - particularly in the browsers which don't render the red border around the checkbox, as they tend to be the ones which are rendering shadows or other fancy effects. Anyway the point is there's now something you can hang your hat on CSS-wise, and that actually shows up in all the major browsers. </p> CSS drupal drupal-planet theme Sat, 04 Sep 2010 14:31:09 +0000 drew 29 at http://mcdruid.co.uk.php53 migrating from oscommerce to ubercart http://mcdruid.co.uk.php53/content/migrating-from-oscommerce-to-ubercart <div class="field field-type-filefield field-field-image"> <div class="field-items"> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/node_import_sample_data.png" alt="stepping through the node import wizard" title="" width="150" height="199" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> </div> </div> <p> I recently undertook a migration from oscommerce to ubercart. The scope of this migration was limited to the transfer of products (and categories) - I didn't try and migrate customers and previous orders. </p> <p> Here's an overview of the procedure I followed:</p> <p><ul> <li>generate a CSV file of categories in oscommerce</li> <li>import into drupal / ubercart using taxonomy_csv module</li> <li>generate a CSV file of product data from oscommerce</li> <li>import into drupal / ubercart using (patched) node_import module</li> </ul> </p><p> My life was made relatively easy by the fact that although the categories in oscommerce had a hierarchical structure, it was very simple. There were only a handful of top-level categories, and the tree was only one deep. Here's what the schema for categories looks like in oscommerce: </p> <p><div class="geshifilter"><pre class="sql geshifilter-sql" style="font-family:monospace;">mysql<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">SHOW</span> <span style="color: #993333; font-weight: bold;">TABLES</span> <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">'categor%'</span>; <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------------------------+</span> <span style="color: #66cc66;">|</span> Tables_in_mysite_osc1 <span style="color: #66cc66;">&#40;</span>categor%<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------------------------+</span> <span style="color: #66cc66;">|</span> categories <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> categories_description <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------------------------+</span> mysql<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">DESCRIBE</span> categories; <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">------------------+-------------+------+-----+---------+----------------+</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">FIELD</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">TYPE</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #66cc66;">|</span> Extra <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">------------------+-------------+------+-----+---------+----------------+</span> <span style="color: #66cc66;">|</span> categories_id <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> NO <span style="color: #66cc66;">|</span> PRI <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> categories_image <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">64</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> YES <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> parent_id <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> NO <span style="color: #66cc66;">|</span> MUL <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> sort_order <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> YES <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> date_added <span style="color: #66cc66;">|</span> datetime <span style="color: #66cc66;">|</span> YES <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> last_modified <span style="color: #66cc66;">|</span> datetime <span style="color: #66cc66;">|</span> YES <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">------------------+-------------+------+-----+---------+----------------+</span> mysql<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">DESCRIBE</span> categories_description; <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------+-------------+------+-----+---------+-------+</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">FIELD</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">TYPE</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #66cc66;">|</span> Extra <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------+-------------+------+-----+---------+-------+</span> <span style="color: #66cc66;">|</span> categories_id <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> NO <span style="color: #66cc66;">|</span> PRI <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> language_id <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> NO <span style="color: #66cc66;">|</span> PRI <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> categories_name <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">|</span> NO <span style="color: #66cc66;">|</span> MUL <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">-----------------+-------------+------+-----+---------+-------+</span></pre></div></p> <p>I had 115 categories, 5 of which were top-level, and the remaining 110 were all children of one of those 5 parents. This meant it was simple to generate the CSV for the import of the category hierarchy into drupal manually; I simply went through my top-level categories and got a list of all their children. All I wanted for the import was the category names. (n.b. I could also ignore language as this site's monolingual.) I did some simple queries to get the names of categories where the parent was one of my top-level categories (which all had a parent_id of 0), e.g.</p> <p><div class="geshifilter"><pre class="sql geshifilter-sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> categories_name <span style="color: #993333; font-weight: bold;">FROM</span> categories c <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> categories_description cd <span style="color: #993333; font-weight: bold;">ON</span> c<span style="color: #66cc66;">.</span>categories_id <span style="color: #66cc66;">=</span> cd<span style="color: #66cc66;">.</span>categories_id <span style="color: #993333; font-weight: bold;">WHERE</span> c<span style="color: #66cc66;">.</span>parent_id <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">31</span>;</pre></div></p> <p>...and prepared a CSV file, a snippet of which is below (where <em>Empire</em> and <em>Europe and Colonies</em> are top-level) I then imported my categories using taxonomy_csv, set to mode <em>Hierarchical tree structure or one term by line structure</em>. node_import can also import taxonomy terms, but unless I'm mistaken it doesn't support hierarchical taxonomies.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">&quot;Empire&quot;, ,&quot;Aden&quot; ,&quot;Antigua&quot; ,&quot;Ascension&quot; ,&quot;Australia&quot; ,&quot;B.O.I.C.&quot; ,&quot;Bahamas&quot; ...snip... &quot;Europe and Colonies&quot;, ,&quot;Austria&quot; ,&quot;Baltic&quot; ,&quot;Benelux&quot; ,&quot;Eastern Europe&quot; ,&quot;France&quot; ...etc...</pre></div></p> <p>Next was my products. I also wanted to use a CSV file to import these into ubercart, so I had to generate a CSV file from the oscommerce database. I wrote a quick php cli script which queries the database, (optionally) grabs product images using CURL from the webserver oscommerce is running on, and outputs a nice CSV file and a folder full of product images (which need to be put in the right place on the drupal/ubercart server). Here's the script:</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">#!/usr/bin/php <span style="color: #000000; font-weight: bold;">&lt;?php</span> &nbsp; <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'CSV_OUTPUT'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/tmp/osc_products.csv'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'DB_HOST'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'localhost'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'DB_NAME'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'mysite_osc1'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'DB_USER'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'root'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'DB_PASS'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'top-secret'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'LIMIT'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1000</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GRAB_IMAGES'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMAGE_REMOTE_PATH'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'http://shop.example.com/images/'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/define"><span style="color: #990000;">define</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMAGE_LOCAL_DIR'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/tmp/osc_images/'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;EOQ SELECT * FROM products p INNER JOIN products_description pd ON p.products_id = pd.products_id INNER JOIN products_to_categories ptc ON p.products_id = ptc.products_id INNER JOIN categories_description cd ON ptc.categories_id = cd.categories_id WHERE p.products_status = 1 EOQ</span><span style="color: #339933;">;</span> <span style="color: #000088;">$query</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">' LIMIT '</span> <span style="color: #339933;">.</span> LIMIT<span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> db_connect<span style="color: #009900;">&#40;</span>DB_HOST<span style="color: #339933;">,</span> DB_NAME<span style="color: #339933;">,</span> DB_USER<span style="color: #339933;">,</span> DB_PASS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$products</span> <span style="color: #339933;">=</span> db_query<span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$counter</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">/* example of results: ( [[products_id]] =&gt; 5656 [[products_quantity]] =&gt; 1 [[products_model]] =&gt; [[products_image]] =&gt; AdenStH.jpg [[products_price]] =&gt; 10.0000 [[products_date_added]] =&gt; 2009-03-16 12:34:00 [[products_last_modified]] =&gt; [[products_date_available]] =&gt; [[products_weight]] =&gt; 0.00 [[products_status]] =&gt; 1 [[products_tax_class_id]] =&gt; 0 [[manufacturers_id]] =&gt; 0 [[products_ordered]] =&gt; 0 [[language_id]] =&gt; 1 [[products_name]] =&gt; N05656 - Ascension : Multifranked to St. Helena 1939 [[products_description]] =&gt; St. Helena receiver dated 1941! Curiosity!! [[products_url]] =&gt; [[products_viewed]] =&gt; 159 [[categories_id]] =&gt; 409 [[categories_name]] =&gt; Ascension ) */</span> &nbsp; <span style="color: #666666; font-style: italic;">// prepare files</span> <span style="color: #000088;">$handle</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/fopen"><span style="color: #990000;">fopen</span></a><span style="color: #009900;">&#40;</span>CSV_OUTPUT<span style="color: #339933;">,</span> <span style="color: #0000ff;">'w'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$columns</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sku'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'date'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'description'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'image'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'price'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'category'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/fputcsv"><span style="color: #990000;">fputcsv</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$handle</span><span style="color: #339933;">,</span> <span style="color: #000088;">$columns</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>GRAB_IMAGES<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><a href="http://www.php.net/is_dir"><span style="color: #990000;">is_dir</span></a><span style="color: #009900;">&#40;</span>IMAGE_LOCAL_DIR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <a href="http://www.php.net/mkdir"><span style="color: #990000;">mkdir</span></a><span style="color: #009900;">&#40;</span>IMAGE_LOCAL_DIR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> db_object<span style="color: #009900;">&#40;</span><span style="color: #000088;">$products</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$counter</span> <span style="color: #339933;">&lt;</span> LIMIT<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//print_r($product);</span> <span style="color: #000088;">$counter</span> <span style="color: #339933;">++;</span> &nbsp; <span style="color: #000088;">$sku</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/substr"><span style="color: #990000;">substr</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_name</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$product_name</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/substr"><span style="color: #990000;">substr</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_name</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">9</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$image_name</span> <span style="color: #339933;">=</span> clean_filename<span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_image</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$data_to_write</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$sku</span><span style="color: #339933;">,</span> <span style="color: #000088;">$product_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_date_added</span><span style="color: #339933;">,</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_description</span><span style="color: #339933;">,</span> <span style="color: #000088;">$image_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_price</span><span style="color: #339933;">,</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">categories_name</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$data_to_write</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array_map"><span style="color: #990000;">array_map</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'trim'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data_to_write</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>GRAB_IMAGES<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>grab_image<span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_image</span><span style="color: #339933;">,</span> <span style="color: #000088;">$image_name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'grabbed '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_image</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot; (<span style="color: #006699; font-weight: bold;">$image_name</span>)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'failed to grab '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$product</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">products_image</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> &nbsp; <a href="http://www.php.net/fputcsv"><span style="color: #990000;">fputcsv</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$handle</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data_to_write</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <a href="http://www.php.net/fclose"><span style="color: #990000;">fclose</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$handle</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;# iterated over <span style="color: #006699; font-weight: bold;">$counter</span> products<span style="color: #000099; font-weight: bold;">\n</span>### END<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/exit"><span style="color: #990000;">exit</span></a><span style="color: #339933;">;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** helper functions **/</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> db_error<span style="color: #009900;">&#40;</span><span style="color: #000088;">$message</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;db_error: <span style="color: #006699; font-weight: bold;">$message</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #339933;">.</span> <a href="http://www.php.net/mysql_error"><span style="color: #990000;">mysql_error</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> db_connect<span style="color: #009900;">&#40;</span><span style="color: #000088;">$db_host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db_user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db_pass</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/mysql_connect"><span style="color: #990000;">mysql_connect</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db_host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db_user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db_pass</span><span style="color: #009900;">&#41;</span> or db_error<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Unable to connect to database'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/mysql_select_db"><span style="color: #990000;">mysql_select_db</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$db</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> db_query<span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/mysql_query"><span style="color: #990000;">mysql_query</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #339933;">,</span> <span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span> or db_error<span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> db_object<span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">return</span> <a href="http://www.php.net/mysql_fetch_object"><span style="color: #990000;">mysql_fetch_object</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> grab_image<span style="color: #009900;">&#40;</span><span style="color: #000088;">$image_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$new_name</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> IMAGE_REMOTE_PATH <span style="color: #339933;">.</span> <span style="color: #000088;">$image_name</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// use curl to grab the image from the server</span> <span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/curl_init"><span style="color: #990000;">curl_init</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <a href="http://www.php.net/curl_setopt"><span style="color: #990000;">curl_setopt</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/curl_setopt"><span style="color: #990000;">curl_setopt</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/curl_exec"><span style="color: #990000;">curl_exec</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.php.net/curl_close"><span style="color: #990000;">curl_close</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/strlen"><span style="color: #990000;">strlen</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$retval</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/file_put_contents"><span style="color: #990000;">file_put_contents</span></a><span style="color: #009900;">&#40;</span>IMAGE_LOCAL_DIR <span style="color: #339933;">.</span> <span style="color: #000088;">$new_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$retval</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$retval</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #000000; font-weight: bold;">function</span> clean_filename<span style="color: #009900;">&#40;</span><span style="color: #000088;">$old_name</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$bad_stuff</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'.JPG'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&amp;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$good_stuff</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'.jpg'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'-'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$new_name</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/str_replace"><span style="color: #990000;">str_replace</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$bad_stuff</span><span style="color: #339933;">,</span> <span style="color: #000088;">$good_stuff</span><span style="color: #339933;">,</span> <span style="color: #000088;">$old_name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$new_name</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <p> You'll see my products had an SKU we'd put into the first part of the title in oscommerce - this should be easy to remove if it's not applicable. The image grabbing requires php-curl - you could just grab a whole image directory off the server running oscommerce, but I wanted to be careful to only migrate images actually being used. There are obviously many other ways of doing this. </p> <p> I had to apply a couple of patches to node_import (rc4) to get it working for me:</p> <ul> <li><a href="http://drupal.org/node/641852" title="http://drupal.org/node/641852" rel="nofollow">http://drupal.org/node/641852</a></li> <li><a href="http://drupal.org/node/383926" title="http://drupal.org/node/383926" rel="nofollow">http://drupal.org/node/383926</a> (removing &gt;&gt; from form)</li> <li><a href="http://drupal.org/node/635788" title="http://drupal.org/node/635788" rel="nofollow">http://drupal.org/node/635788</a></li> </ul> <p>...I also set escape char to \ (when using fputcsv in my script). After all that, I was able to follow the node_import wizard, mapping fields in the CSV to fields in my ubercart product content type, after which the imported successfully digested my CSV, and all my products appeared with their images in my new ubercart site (I obviously had to put the images my script had grabbed into the right place on the ubercart webserver as well). </p> drupal drupal-planet ecommerce migration oscommerce ubercart Tue, 27 Jul 2010 11:42:53 +0000 drew 28 at http://mcdruid.co.uk.php53 installing APC on Ubuntu linux and benchmarking Drupal 6 performance improvement http://mcdruid.co.uk.php53/content/installing-apc-on-ubuntu-linux-and-benchmarking-drupal-6-performance-improvement <div class="field field-type-filefield field-field-image"> <div class="field-items"> <div class="field-item odd"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/apc.php_.png" alt="APC graphs" title="" width="150" height="120" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> <div class="field-item even"> <img src="http://mcdruid.co.uk.php53/sites/mcdruid.co.uk.php53/files/imagecache/thumbnails/sites/mcdruid.co.uk/files/images/apc_entries.png" alt="APC entries" title="" width="150" height="120" class="imagecache imagecache-thumbnails imagecache-default imagecache-thumbnails_default"/> </div> </div> </div> <p>There are several different <a href="http://en.wikipedia.org/wiki/List_of_PHP_accelerators" rel="nofollow">PHP accelerators</a> to choose from, but according to wikipedia <em>"APC is quickly becoming the de-facto standard PHP caching mechanism as it will be included built-in to the core of PHP starting with PHP 6"</em>.</p> <p>I recently put together a new development webserver in a virtualbox virtual machine, and as I was setting it up I thought I'd take the opportunity to test how much difference APC actually makes to a simple Drupal site.</p> <h3>Installation</h3> <p>I was using Ubuntu server. On newer releases APC is available from the package manager...</p> <p class="code">$ apt-cache search php-apc<br /> php-apc - APC (Alternative PHP Cache) module for PHP 5<br /> $ sudo apt-get install php-apc</p> <p>...however I'm using Ubuntu 8.04 LTS (Hardy Heron) and there's no apc-php package. It's not hard to install via PECL / PEAR though. First some dependencies need to be installed, then PECL can be used to install APC.</p> <p class="code">$ sudo apt-get install php-pear php5-dev apache2-threaded-dev build-essential<br /> $ sudo pecl install apc</p> <p>This last command will produce a ton of output, but one of the last lines will tell you to add this to your php.ini file (which you'll find in /etc/php5/apache2/php.ini) - you'll probably have to do so manually.</p> <p class="code">extension=apc.so</p> <p>Restart apache, and you should see a new APC section in phpinfo() which will confirm it's enabled. There's a small php script which gives you some useful info about APC, which you'll find in <em>/usr/share/php/apc.php</em> - you could use a symlink to allow you to get to this file in your browser to see the stats and graphs it produces to tell you what files it has cached, and info on cache hits and misses.</p> <h3>What difference does it make?</h3> <p>I've left the APC default settings - which in my case was only 30mb of memory being used for cache, and run some basic tests using <a href="http://httpd.apache.org/docs/2.0/programs/ab.html" rel="nofollow">Apache Bench</a> on a simple Drupal 6 site. The actual performance figures are not that important (this is a virtual machine on my laptop, not a production server), but it's interesting to see how much difference it makes turning APC on.</p> <p>I tested two pages - the very simple homepage, and another page which displays a relatively long webform. The AB command I used was for 100 requests with 10 concurrent requests. e.g.</p> <p class="code">$ ab -n 100 -c 10 <a href="http://mytestsite.example/webform/" title="http://mytestsite.example/webform/" rel="nofollow">http://mytestsite.example/webform/</a></p> <table class="tochart typebvg size700x250 dont-hide"> <caption>test of APC on a Drupal 6 site</caption> <thead> <tr> <th scope="col">Test</th> <th scope="col">Requests / Second</th> </tr> </thead> <tbody> <tr> <td>homepage (APC off)</td> <td>2.78</td> </tr> <tr> <td>webform (APC off)</td> <td>1.72</td> </tr> <tr> <td>homepage (APC on)</td> <td>8.36</td> </tr> <tr> <td>webform (APC on)</td> <td>3.77</td> </tr> </tbody> </table> <table class="tochart typebvg size700x250 dont-hide"> <caption>test of APC on a Drupal 6 site</caption> <thead> <tr> <th scope="col">Test</th> <th scope="col">Milliseconds / Request</th> </tr> </thead> <tbody> <tr> <td>homepage (APC off)</td> <td>359.68</td> </tr> <tr> <td>webform (APC off)</td> <td>582.94</td> </tr> <tr> <td>homepage (APC on)</td> <td>119.61</td> </tr> <tr> <td>webform (APC on)</td> <td>265.41</td> </tr> </tbody> </table> <p>You can see that the effect of APC on the simple homepage is more dramatic than on the webform page. This is almost certainly because the database has to do a lot more work to build the latter, and APC's not going to help on that front. However, we can say on the simple page APC makes Drupal perform almost 3 times faster. With the more database-heavy webform page, the improvement is slightly less - but we're still looking at a doubling in performance.</p> <p>This is obviously not a hugely detailed test, but it certainly leaves me in no doubt that installing APC represents a quick and easy way to achieve a huge improvement in performance for Drupal sites.</p> apc drupal drupal-planet drupal6 performance ubuntu Sun, 04 Jul 2010 15:22:42 +0000 drew 27 at http://mcdruid.co.uk.php53