<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Alt om ingenting og litt i mellom &#187; PHP</title>
	<atom:link href="http://hovenko.no/blog/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>https://hovenko.no/blog</link>
	<description>En blogg av Knut-Olav</description>
	<lastBuildDate>Mon, 10 Mar 2025 19:25:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>How to build PHP extension tidy as shared object</title>
		<link>https://hovenko.no/blog/2010/10/26/how-to-build-php-extension-tidy-as-shared-object/</link>
		<comments>https://hovenko.no/blog/2010/10/26/how-to-build-php-extension-tidy-as-shared-object/#comments</comments>
		<pubDate>Tue, 26 Oct 2010 11:31:26 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[English-posts]]></category>
		<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://hovenko.no/blog/?p=487</guid>
		<description><![CDATA[If you already got a PHP installation setup, you may need another extension/module from the PHP source tree. You can build and install that single module from the source while keeping the rest of the PHP installation intact, but the documentation of building shared PHP modules is poor. In my case I needed the tidy [...]]]></description>
			<content:encoded><![CDATA[<p>If you already got a PHP installation setup, you may need another extension/module from the PHP source tree.</p>
<p>You can build and install that single module from the source while keeping the rest of the PHP installation intact, but the documentation of building shared PHP modules is poor.</p>
<p>In my case I needed the <em>tidy</em> extension, and here&#8217;s how to do it</p>
<pre><code>
 $ # extract the PHP source code and enter the directory
 $ ./configure --with-tidy=shared
 $ find . -name tidy.so
</code></pre>
<p>Then copy the tidy.so file to the modules directory of the PHP installation.</p>
<p>The important part here is the <em>shared</em> keyword, which is poorly documented. I had to inspect a RPM spec file to figure it out.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2010/10/26/how-to-build-php-extension-tidy-as-shared-object/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL, PHP, MDB2 og NULL-problemer</title>
		<link>https://hovenko.no/blog/2010/10/02/mysql-php-mdb2-og-null-problemer/</link>
		<comments>https://hovenko.no/blog/2010/10/02/mysql-php-mdb2-og-null-problemer/#comments</comments>
		<pubDate>Sat, 02 Oct 2010 14:27:48 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[kompatibilitet]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://hovenko.no/blog/?p=478</guid>
		<description><![CDATA[MDB2 har en fin kompatibilitetsliste for å kompansere for problemer i Oracle SQL, men disse er også aktivert for andre databaser. Med andre ord så blir tomme strenger (&#8220;&#8221;) behandlet som NULL. Dermed rapporterer MySQL med en feilmelding dersom du forsøker å sette en tom streng i et &#8220;NOT NULL&#8221;-felt. Hurra! Heldigvis går det an [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://pear.php.net/MDB2/">MDB2</a> har en fin kompatibilitetsliste for å kompansere for problemer i Oracle SQL, men disse er også aktivert for andre databaser.</p>
<p>Med andre ord så blir tomme strenger (&#8220;&#8221;) behandlet som NULL. Dermed rapporterer MySQL med en feilmelding dersom du forsøker å sette en tom streng i et &#8220;NOT NULL&#8221;-felt. Hurra!</p>
<p>Heldigvis går det an å <a href="http://stackoverflow.com/questions/266431/empty-string-in-not-null-column-in-mysql/266545#266545">skru av kompatibilitetslagene i MDB2</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2010/10/02/mysql-php-mdb2-og-null-problemer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Slik lurer man PHP Magic Quotes</title>
		<link>https://hovenko.no/blog/2008/09/20/slik-lurer-man-php-magic-quotes/</link>
		<comments>https://hovenko.no/blog/2008/09/20/slik-lurer-man-php-magic-quotes/#comments</comments>
		<pubDate>Sat, 20 Sep 2008 00:41:15 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[sikkerhet]]></category>

		<guid isPermaLink="false">http://hovenko.no/blog/?p=166</guid>
		<description><![CDATA[Det er fredag kveld, jeg sitter hos en kamerat og progger litt Perl. Så begynte vi å titte litt på hvilke Firefox plugins vi kjørte og fant ut at vi begge hadde Firebug, Web Developer og Download Statusbar. Videre har jeg også en Firefox plugin som heter XSS Me. Da bestemte jeg meg for å [...]]]></description>
			<content:encoded><![CDATA[<p>Det er fredag kveld, jeg sitter hos en kamerat og progger litt Perl. Så begynte vi å titte litt på hvilke Firefox plugins vi kjørte og fant ut at vi begge hadde <a href="https://addons.mozilla.org/firefox/addon/1843" title="Last ned Firefox plugin Firebug">Firebug</a>, <a href="https://addons.mozilla.org/en-US/firefox/addon/60" title="Last ned Firefox plugin Web Developer">Web Developer</a> og <a href="https://addons.mozilla.org/en-US/firefox/addon/26" title="Last ned Firefox plugin Download Statusbar">Download Statusbar</a>. Videre har jeg også en Firefox plugin som heter <a href="https://addons.mozilla.org/en-US/firefox/addon/7598" title="Last ned Firefox plugin XSS Me">XSS Me</a>.</p>
<p>Da bestemte jeg meg for å teste Perl-applikasjonen min for sikkerhetshull. Denne applikasjonen er svært enkel. Den har ett HTML-skjema med ett input-felt, og data fra dette feltet blir listet ut på forsiden. &#8220;Shout&#8221; heter det, enkelt og greit. Jeg fyrte avgårde alle testene i XSS Me mot dette skjemaet og fikk ørten sikkerhetsvarslinger i retur. Dette løste jeg riktignok med en enkel pipe igjennom html-filteret til Template Toolkit.</p>
<p>Vi utforsket dette videre. Kameraten min smalt opp et lite PHP-script som tok innholdet fra et textarea-felt og viste det uendret ut på HTML-sida. Vi fant fort ut at PHP gjorde noe magisk bak scenen, som PHP så gjerne ofte gjør; magic quotes heter det. Men jeg lurte jæveln&#8230;</p>
<p><code><br />
&lt;script&gt;<br />
&nbsp;window.location=String.fromCharCode(104)<br />
&nbsp;&nbsp;+ String.fromCharCode(116)<br />
&nbsp;&nbsp;+ String.fromCharCode(116)<br />
&nbsp;&nbsp;+ String.fromCharCode(112)<br />
&nbsp;&nbsp;+ String.fromCharCode(58)<br />
&nbsp;&nbsp;+ String.fromCharCode(47)<br />
&nbsp;&nbsp;+ String.fromCharCode(47)<br />
&nbsp;&nbsp;+ String.fromCharCode(103)<br />
&nbsp;&nbsp;+ String.fromCharCode(111)<br />
&nbsp;&nbsp;+ String.fromCharCode(111)<br />
&nbsp;&nbsp;+ String.fromCharCode(103)<br />
&nbsp;&nbsp;+ String.fromCharCode(108)<br />
&nbsp;&nbsp;+ String.fromCharCode(101)<br />
&nbsp;&nbsp;+ String.fromCharCode(46)<br />
&nbsp;&nbsp;+ String.fromCharCode(99)<br />
&nbsp;&nbsp;+ String.fromCharCode(111)<br />
&nbsp;&nbsp;+ String.fromCharCode(109);<br />
&lt;/script&gt;<br />
</code></p>
<p>Denne koden dekoder tallene til tegn, setter dem sammen til en tekststreng, tilordner tekststrengen til &#8220;document.location&#8221;. Javascriptet sender deg så videre til en ny nettside, rett og slett til <a href="http://google.com">http://google.com</a>.</p>
<p><small>Ironisk nok klarte jeg å <em>redirecte meg selv</em> til google da jeg skulle ta en titt på preview&#8217;n på dette innlegget. Glemte visst å enkode HTML-taggene, tenke seg det&#8230;</small></p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2008/09/20/slik-lurer-man-php-magic-quotes/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Web frameworks – Comparing Catalyst and Symfony</title>
		<link>https://hovenko.no/blog/2008/02/01/web-frameworks-%e2%80%93-comparing-catalyst-and-symfony/</link>
		<comments>https://hovenko.no/blog/2008/02/01/web-frameworks-%e2%80%93-comparing-catalyst-and-symfony/#comments</comments>
		<pubDate>Thu, 31 Jan 2008 23:56:32 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Web Framework]]></category>

		<guid isPermaLink="false">http://www.hoven.ws/blog/2008/02/01/web-frameworks-%e2%80%93-comparing-catalyst-and-symfony/</guid>
		<description><![CDATA[Ruby on Rails has become unbelievably popular the last couple of years. It divides applications into three layers; models, views and controllers, or the shorter term MVC. This means that the presentation is separated from the application logic and the data. It seems that everyone wants to make their own Ruby on Rails clone, and [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby on Rails has become unbelievably popular the last couple of years. It divides applications into three layers; models, views and controllers, or the shorter term MVC. This means that the presentation is separated from the application logic and the data. It seems that everyone wants to make their own Ruby on Rails clone, and similar web frameworks exists now for Java, PHP, Perl and Python, to name some. I have some experience with Ruby on Rails myself, but most ever learned is now forgotten. I am not going to talk about Ruby on Rails, but about two offsprings; Catalyst and Symfony.</p>
<p>I have worked with <a href="http://catalyst.perl.org/">Catalyst</a> the last two months, and I have become very comfortable with its MVC implementation. Almost everything is based on components, and Catalyst presents convenient methods for accessing controllers, models and views. Plugins can extend the core functionality of Catalyst by providing methods for easy access, for example to localize strings or assemble HTML widgets and forms. Methods imported from plugins are directly accessible from the context object to all components in your system. You can also create your own plugins, for example to access a cache solution.</p>
<p><a href="http://www.symfony-project.org/">Symfony</a> is based on many of the same principles as Catalyst, to separate views, controllers and models from each other. Plugins can be used to extend the functionality, but not only for the core. If you want to integrate with a database using an ORM-solution (object relational mapping), as many do when using a web framework, you have to include a plugin for that. You don&#8217;t have to, but there are already plugins for this functionality, and you don&#8217;t want to reinvent the wheel, do you?</p>
<p><span id="more-104"></span></p>
<p>The most obvious difference between Catalyst and Symfony are that they are written in different languages, Perl and PHP respectively. URL mapping in Catalyst is handled in each controller by defining the dispatch type in the method signature. The default is to map URLs to controller names, and because of the namespace support in Perl known as packages, this makes it easier to create hierarchical structures in Catalyst. This means that you can create controllers with deeply nested actions in a clean and logical way. An example of this can be taken from the <a href="http://www.hoven.ws/blog/2008/01/24/presenting-bifrost-follow-me-printing-and-printout-management/">Bifrost project</a> where the URL &#8220;http://example.com/admin/cards/lastswipe/create&#8221; is mapped to the package &#8220;Controller::Admin::Cards::Lastswipe::Create&#8221;.</p>
<p>PHP has no knowledge of namespace, and Symfony does therefore only support two levels in the controller view; modules with one or more actions. It does however map URLs to actions using a configuration file, so it is possible to get multilevel URLs in Symfony too. Because of the mapping configuration it is not always given that the example URL above maps to a class named &#8220;AdminCardsLastswipe&#8221;, it could just as well be mapped to something like &#8220;fooBar&#8221;. This gives flexibility to the applications, because URLs can stay the same even if the files are move. This is also achievable in Catalyst as well, but would be an exception of the normal rules, and can be spotted when starting up the application server in debug mode. As long as only you are working on the project this is not a big problem, but it might be harder for others to understand it. You might even get problems yourself if the application grows very large.</p>
<p>When it comes to the model layer, a common practice with Catalyst is to implement a small model class, used to invoke a model class or sub system with configuration parameters, user session attributes or request attributes. To retrieve a model you call $c->model(&#8220;MyModel&#8221;). This is also true for the view layer where you access the view sub system by calling something like $c->view(&#8220;TT&#8221;). Normally you won&#8217;t have to explicitly call on the view, because it will automatically use the one available, or the one configured as the default view if you use multiple views.</p>
<p>In Symfony, the view and model layers are included as plugins to extend the core. This locks you in to use only one view and one model implementation for each application. You can of course implement new methods to return what ever you want, but then you go outside the scope of Symfony. In fact, an ORM called Propel is already integrated in Symfony, and you need to use a plugin to override this behaviour. From what I can see from configuration files, you can only use model in your application. You can probably configure each module to use different models, but you are still stuck if you want to search in two databases from a single action. This brings me over to the next part; flow control.</p>
<p>Actions in Catalyst are methods in controller modules. You can forward to other actions, and the original flow of execution is resumed when the actions end. This gives you flexibility to gather data from multiple actions without being cut off. If you detach to other actions, the chain will break off and won&#8217;t resume to the original action. If an action you forward or detach to throws an exception, the exception is thrown back through the action stack, which. This makes it easier to catch and handle exceptions because the exception will always end up in the first action method.</p>
<p>In Symfony, actions are methods in modules. When forwarding you get the same effect as detach in Catalyst. You can use filters in Symfony to achieve some of the same effect as forwarding in Catalyst. The difference is that you have not reached your action yet when running through your pre-filters, which means you can not handle exceptions in your action class. Filters are often used for caching, authentication and authorization.</p>
<p>Perl has a template framework called Template Toolkit which separates application logic from presentation. What I like about Template Toolkit is that there is no need for any Perl syntax inside the template files, which I believe is important when graphical designers are working on the templates. There are also other template systems for Perl, for example HTML Template.</p>
<p>Symfony uses a template system which depends on PHP to print variables, handle flow control and to call view helpers, but using PHP in the template files can result in unpleasant results if used to handle too much of the flow control. A thumb rule might be to never let PHP code exceed more than one line at a time in the template files. It is possible to use Smarty, a template system with many of the same features as Template Toolkit. It is also possible to use XML and XSLT in the view layer, but traversing XML files can be a tough experience for most people.</p>
<p>Now, lets focus back on MVC frameworks and Ruby on Rails. Of the two web frameworks I have discussed above, Symfony is the one that looks most like Ruby on Rails, but that doesn&#8217;t mean it&#8217;s perfect. Catalyst has a stronger separation between the layers, which provides more flexibility, and I like that. When working on Bifrost we had to integrate with multiple sources of information, such as LDAP for data storage, ARP for looking up MAC addresses and CUPS for listing printers and printing documents from web forms. This was all done in models. If this had been done in Symfony, we had to implement those features directly into the controller layer or create a lot of plugins.</p>
<p>The world of web frameworks is large, and it is definitely worth learning to use some of them. It didn&#8217;t take long before I was able to understand Catalyst and use it effectively. It has taken a little longer with Symfony, probably because I find PHP harder to use, because of inconsistent function and configuration names and the lack of namespaces. Symfony focuses a lot on caching to optimize for speed, and this is of course needed because the entire framework gets loaded on each page request. I find Catalyst more elegant than Symfony, not only because of the programming language, but also because Catalyst focuses more on good software design and that it pre-loads the framework and components once, and then forks to multiple daemon processes to share memory and save resources.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2008/02/01/web-frameworks-%e2%80%93-comparing-catalyst-and-symfony/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress plugins &#8211; katalogstruktur</title>
		<link>https://hovenko.no/blog/2007/06/07/wordpress-plugins-katalogstruktur/</link>
		<comments>https://hovenko.no/blog/2007/06/07/wordpress-plugins-katalogstruktur/#comments</comments>
		<pubDate>Wed, 06 Jun 2007 22:54:43 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[katalogstruktur]]></category>
		<category><![CDATA[kontroller]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[ytelse]]></category>

		<guid isPermaLink="false">http://www.hoven.ws/blog/2007/06/07/wordpress-plugins-katalogstruktur/</guid>
		<description><![CDATA[Når man utvikler en plugin for WordPress som stadig utvides med ny funksjonalitet kan den vokse så stor at det kan bli et uhåndterbart antall filer i pluginkatalogen eller at filene rett og slett blir så store at det er vanskelig å få oversikt over funksjonaliteten i filene. Dette går også ut over ytelsen til [...]]]></description>
			<content:encoded><![CDATA[<p>Når man utvikler en <a href="http://codex.wordpress.org/Writing_a_Plugin">plugin</a> for <a href="http://www.wordpress.org">WordPress</a> som stadig utvides med ny funksjonalitet kan den vokse så stor at det kan bli et uhåndterbart antall filer i pluginkatalogen eller at filene rett og slett blir så store at det er vanskelig å få oversikt over funksjonaliteten i filene. Dette går også ut over ytelsen til WordPress. Et eksempel er plugin-siden i administrasjonsgrensesnittet som søker i alle PHP-filer i alle underkataloger ett nivå under plugins-katalogen etter filer med en <a href="http://codex.wordpress.org/Writing_a_Plugin#File_Headers">plugin-header</a>.</p>
<p>Dersom man kun beholder én PHP-fil, som vi kaller for &#8220;loader&#8221;, i rotkatalogen til pluginen kan ytelsen økes noe. Denne filen inneholer plugin-headeren og den eneste oppgaven til denne filen er å laste de resterende filene i pluginen. Denne loaderen vil videre laste en kontroller i en katalog vi kan kalle for &#8220;core&#8221;. Denne kontrolleren har som oppgave å sette opp hooks for å intregere mot WordPress og ellers kontrollere dataflyten i pluginen.</p>
<p>Den viktigste grunnen for å organisere filene sine er for å få bedre oversikt. En måte å gjøre dette på er å benytte underkataloger basert på funksjonalitet og filtype. For eksempel kan man plassere alle Javascript-filer i en &#8220;js&#8221;-katalog og alle CSS-filer i en &#8220;css&#8221;-katalog. Dersom pluginen din skal ha et administrasjonsgrensesnitt kan disse filene legges i katalogen &#8220;admin&#8221;, og en widget-støttet plugin kan ha widget-relaterte filer i en &#8220;widget&#8221;-katalog. All denne strukturen krever litt ekstra koding og flere filer å holde styr på, men til gjengjeld slipper man å se sine filer vokse til store monstere på flere tusen linjer. Store filer kan lett bli et problem, noe jeg selv har erfart i utvikling av WordPress-plugins.</p>
<p>Eksempel på katalogstruktur for en plugin av passe stor størrelse:<br />
<code><br />
my_plugin_loader.php<br />
/actions/controller.php<br />
/actions/widget.ajax.php<br />
/admin/options.php<br />
/core/my_plugin.php<br />
/css/admin.options.css<br />
/css/widget-css.php<br />
/js/script-loader.php<br />
/js/some_lib.js<br />
/js/widget-js.php<br />
/languages/my_plugin-nb_NO.po<br />
/languages/my_plugin-nb_NO.mo<br />
/widget/widget.control.php<br />
/widget/widget.php<br />
</code></p>
<p>Jeg har her brukt noen passende filnavn. Det er ofte ikke nødvendig å spesifisere katalognavnet som en del av filnavnet, men av og til kan det være smart, avhengig av hvilken editor som benyttes. Selv benytter jeg Eclipse som viser kun filnavnet, og det kan være vanskelig å skille tre åpne filer som alle heter &#8220;control.php&#8221; fra hverandre.</p>
<p>Jeg har tatt med i eksempelet en fil som heter &#8220;script-loader.php&#8221; som kan benyttes for å laste Javascript-filene. WordPress har funksjonalitet for å registrere Javascriptene med navn, URL og avhengigheter. Det er også mulig å spesifisere versjon av Javascriptet, som blir en del av URL-adressen til filen. Dette er svært aktuelt for å tvinge nettlesere til å laste den nye Javascript-filen fremfor å benytte en som kan finnes i en cache ett eller annet sted.</p>
<p>Man kan ha behov for å kalle på funksjonalitet i pluginen som ikke skal benytte det vanlige themet til WordPress, men kanskje bare returnere noe data til et Javascript, utføre en oppdatering eller printe ut en CSS- eller Javascript-fil. Man kan dermed ha behov for en egen <a href="http://www.hoven.ws/blog/2007/03/08/wordpress-plugins-front-controller/">front-kontroller</a> som tar seg av disse forespørslene.</p>
<p>Jeg benytter PHP5 og objektorientering for å utvikle plugins til WordPress, men tankene og forslagene i denne artikkelen kan like gjerne benyttes med en strukturell programmeringsmetodikk. Jeg synes det er alt for mange dårlig skrevne plugins for WordPress, hacket sammen for å gi funksjonaliteten som er ønsket på det gitte tidspunktet. Dette gjør det vanskeligere å vedlikeholde dem senere når nye krav kommer og det gjør integrasjon med andre plugins og nyere versjoner av WordPress til et mareritt. Disse pluginene benyttes så som et utgangspunkt for nye plugins ved hjelp av copy/paste-metoden. Jeg tror at bedre dokumentasjon med gode eksempler kan bidra til bedre kodestandard på plugins.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2007/06/07/wordpress-plugins-katalogstruktur/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress plugins &#8211; Front Controller</title>
		<link>https://hovenko.no/blog/2007/03/08/wordpress-plugins-front-controller/</link>
		<comments>https://hovenko.no/blog/2007/03/08/wordpress-plugins-front-controller/#comments</comments>
		<pubDate>Thu, 08 Mar 2007 21:05:05 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Jobb]]></category>
		<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[pattern]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">/blog/2007/03/08/wordpress-plugins-front-controller/</guid>
		<description><![CDATA[WordPress støtter utvidelser via plugins. Plugins kommuniserer med WordPress-kjernen ved å hekte seg på kroker (hooks). Disse krokene blir eksekvert visse steder i koden, for eksempel når en side med poster skal vises, når en bruker opprettes eller når en post slettes. Det er en handlingskrok (action hook) som heter &#8220;init&#8221; som blir kalt på [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.wordpress.org">WordPress</a> støtter utvidelser via plugins. Plugins kommuniserer med WordPress-kjernen ved å hekte seg på kroker (hooks). Disse krokene blir eksekvert visse steder i koden, for eksempel når en side med poster skal vises,  når en bruker opprettes eller når en post slettes.</p>
<p>Det er en handlingskrok (action hook) som heter &#8220;init&#8221; som blir kalt på rett før themet skal lastes inn for presentasjon av postene. Når denne kroken skal eksekveres er plugins lastet og innstillinger lest fra databasen, så denne kroken egner seg svært godt for det jeg nå skal vise, nemlig hvordan man kan kalle på funksjoner i sin egen plugin med via lenker på siden, med HTML forms eller via Javascript og AJAX.</p>
<p>Jeg har ofte hatt behov for å kalle på funksjoner i min plugin fra Javascript på siden, også kjent som Ajax/Web2.0. Jeg har utviklet en plugin som lar brukeren sette et filter, slik at kun innlegg som matcher dette filteret vil bli vist. Jeg skrev denne pluginen på jobben og den er foreløpig kun for internt bruk og er derfor ikke tilgjengelig, men det hindrer meg ikke i å forklare hvordan jeg har brukt denne teknikken.</p>
<p>Dette filteret settes i cookie i nettleseren til brukeren slik at filteret er aktivt helt til brukeren bytter til et annet filter. Filtere kan ligge i nivåer underhverandre. Tenk på det som kategoriene i WordPress, hvor kategorier kan ha en forelderkategori. Jeg skal her vise to eksempler hvor jeg først bruker en link for å bytte til et annet filter, for så å vise hvordan jeg bruker AJAX for å hente en liste med filter.</p>
<p>Linken for å bytte filter kan for eksempel se slik ut:<br />
<code><br />
&lt;a href="http://example.com/?myplugin=set&#038;filter=sport"&gt;Sport&lt;/a&gt;<br />
</code></p>
<p>Da har jeg behov for en sjekk i min plugin, som jeg har valgt å kalle &#8220;myplugin&#8221; (ja, jeg vet, men dette er ikke navnet på min ekte plugin <img src='https://hovenko.no/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ), for å kunne snappe opp ønsket om å bytte filteret til &#8220;sport&#8221;. Jeg har valgt kodeordet &#8220;myplugin&#8221;, det samme som navnet på pluginen jeg har skrevet for å minke risikoen for navnekollisjon. Jeg har en funksjon jeg har hengt på &#8220;init&#8221;-kroken som sjekker om kodeordet er blitt angitt i adressen samt om det finnes en passende handling å utføre.</p>
<p>I eksempelet nedenfor viser jeg også PHP-kode som tar i mot ønsket om å liste ut alle filtere som har et angitt filter som forelder. Legg merke til dersom testen matcher &#8216;list&#8217; vil den printe ut listen for så å dø, hardt og brutalt. Dette er faktisk ønskelig fordi vi skal utføre et asynkront kall med Javascript, noe som betyr at nettsiden ikke skal lastes på nytt, men bare en liten del av nettsiden skal oppdateres. Det som PHP-scriptet skriver ut i eksempelet nedenfor blir hentet opp av Javascriptet som utførte kallet, klar til å inkluderes på nettsiden. Om det er en &lt;select&gt;-liste, en rekke med checkboxer eller noe annet som gjøres med denne listen bestemmes av Javascriptet.</p>
<pre>
<code>
$myplugin = new MyPlugin();
add_action('init', array(&#038;$myplugin, 'check_action'));
//
// Hovedklassen i min plugin
class MyPlugin {
    function check_action() {
        $action = _REQUEST['myplugin'];
        switch($action) {
            case 'set':
                $this->set_filter($_REQUEST['filter']);
                break;
            case 'list':
                $list = $this->get_list($_REQUEST['parent']);
                echo $list;
                exit;
        }
    }
    // Setter nytt filter
    function set_filter($filter = '') {
        // Setter en cookie for brukerens nettleser
    }
    // Returnerer en liste med filtere som har en angitt forelder
    function get_list($parent = '') {
        // finner og returnerer listen med angitt forelder
    }
}
</code>
</pre>
<p>Hvordan Javascriptet som utfører dette asynkrone kallet er programmert skal jeg ikke komme inn på her. Det er et for stort tema å skrive om i denne artikkelen, men det finnes gode ressurser på Internett om AJAX, <a href="http://www.google.com">Google</a> vet det meste. Det kan være verdt å sjekke ut <a href="http://www.scss.com.au/family/andrew/webdesign/xmlhttprequest/">Cross-Browser XMLHttpRequest</a>, som gjør det enklere å bruke Ajax uten at man vrir seg i smerte over de mange forskjellige teknikkene som er brukt i nettlesere.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2007/03/08/wordpress-plugins-front-controller/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Konvertere mellom store og små bokstaver i PHP med mb_convert_case / strtolower</title>
		<link>https://hovenko.no/blog/2007/03/07/konvertere-mellom-store-og-sma-bokstaver-i-php-med-mb_convert_case-strtolower/</link>
		<comments>https://hovenko.no/blog/2007/03/07/konvertere-mellom-store-og-sma-bokstaver-i-php-med-mb_convert_case-strtolower/#comments</comments>
		<pubDate>Wed, 07 Mar 2007 21:45:52 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[konvertering]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tegnsett]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[UTF-8]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">/blog/2007/03/07/konvertere-mellom-store-og-sma-bokstaver-i-php-med-mb_convert_case-strtolower/</guid>
		<description><![CDATA[Jeg følger opp gårsdagens innlegg med et nytt PHP-tips, denne gangen for å konvertere mellom store og små bokstaver. Til dette kan funksjonen mb_convert_case benyttes. Dersom man utvikler nettsider som skal ha støtte for flere språk er det vanskelig å komme utenom UTF-8, unicode. Ofte vil man teste på en variabel om den matcher et [...]]]></description>
			<content:encoded><![CDATA[<p>Jeg følger opp <a href="/blog/2007/03/07/eaccelerator-en-php-akselerator/">gårsdagens innlegg</a> med et nytt PHP-tips, denne gangen for å konvertere mellom store og små bokstaver. Til dette kan funksjonen <a href="http://www.php.net/mb_convert_case"><em>mb_convert_case</em></a> benyttes.</p>
<p>Dersom man utvikler nettsider som skal ha støtte for flere språk er det vanskelig å komme utenom UTF-8, unicode. Ofte vil man teste på en variabel om den matcher et sett med konstanter eller andre variable som brukere skriver inn. Brukere er generelt sett svært ustabile når det gjelder hva input som kan komme inn til serveren, spesielt når det gjelder bruk av store og små bokstaver.</p>
<p>Et eksempel på dette er tagger i WordPress. Hvorfor skal man måtte ha to separate tagger som betyr det samme bare fordi den ene ble skrevet med stor forbokstav mens den andre med liten? Her kan det være kjekt å bruke PHP-funksjonen strtolower, helt til man kommer til spesielle bokstaver og tegn som ikke finnes i tegnsettet man normalt bruker, ofte ISO-8859-1 av en variant. Dette kan fungere greit dersom teksten som kommer inn er i samme tegnsett som serveren benytter, men når det gjelder unicode så er saken annerledes.</p>
<p>Strenger eier ingen informasjon om hvilket tegnsett som benyttes, dette må utviklere holde orden på. Funksjonen strtolower takler unicode svært dårlig. Spesielle tegn, som de norske bokstavene <em>æøåÆØÅ</em>, kodes i unicode med lengden av to vanlige bokstaver. Dette fører til at strtolower deler disse tegnene i to før den utfører konverteringen. Resultatet av dette blir mest sannsynlig et uventet tegn som nettleseren har problemet med å vise. Selv har jeg sett <em>?</em>-tegnet ganske ofte <img src='https://hovenko.no/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Løsningen rundt dette problemet er å benytte PHP-funksjonen <em>mb_convert_case</em>. Som vist i eksempelet konverteres tekststrengen til små bokstaver, lowercase:</p>
<p><code><br />
// UTF-8 tekststreng<br />
$orig_string = 'Hei på deg. Hvordan er været i Østfold?';<br />
$new_lower = mb_convert_case($orig_string, MB_CASE_LOWER, 'UTF-8');<br />
echo $new_lower;<br />
</code></p>
<p>Funksjonen echo vil her skrive ut: <em>hei på deg. hvordan er været i østfold?</em></p>
<p>Den første parameteren til mb_convert_case er tekststrengen som skal konverteres, mens den andre angir hvilken type konvertering som skal utføres, i form av en konstant. Følgende konstanter kan gis til mb_convert_case:</p>
<ul>
<li>MB_CASE_LOWER: konvertere til små bokstaver</li>
<li>MB_CASE_UPPER: konvertere til store bokstaver</li>
<li>MB_CASE_TITLE: konvertere til stor forbokstav i hvert ord</li>
</ul>
<p>Funksjonen mb_convert_case tar også en parameter som forteller hvilket tegnsett som ønskes brukt ved konvertering. På noen forum og mailinglister foreslås det at man kan bruke funksjonen <em>setlocale</em> før strtolower for å sette hvilket tegnsett som skal benyttes, men dette hjalp ikke i mitt tilfelle. Funksjonen mb_convert_case tar utgangspunkt i at tekststrengen er i unicode og klarer derfor å konvertere norske spesialtegn på en utmerket måte.</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2007/03/07/konvertere-mellom-store-og-sma-bokstaver-i-php-med-mb_convert_case-strtolower/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>eAccelerator &#8211; en PHP-akselerator</title>
		<link>https://hovenko.no/blog/2007/03/07/eaccelerator-en-php-akselerator/</link>
		<comments>https://hovenko.no/blog/2007/03/07/eaccelerator-en-php-akselerator/#comments</comments>
		<pubDate>Tue, 06 Mar 2007 23:04:04 +0000</pubDate>
		<dc:creator>Knut-Olav</dc:creator>
				<category><![CDATA[Jobb]]></category>
		<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[akselerator]]></category>
		<category><![CDATA[eAccelerator]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">/blog/2007/03/07/eaccelerator-en-php-akselerator/</guid>
		<description><![CDATA[Jeg har utviklet en nettside, basert på WordPress, hvor vi hadde et problem med at den brukte alt for lang tid på å levere sidene til brukere, selv med bare 10-15 samtidige brukere. Problemet lå på Apache, som fikk serverloaden opp i omkring 7-8. Oppslag av hostnames i Apache var skrudd av og loggfilene var [...]]]></description>
			<content:encoded><![CDATA[<p>Jeg har utviklet en nettside, basert på <a href="http://www.wordpress.org">WordPress</a>, hvor vi hadde et problem med at den brukte alt for lang tid på å levere sidene til brukere, selv med bare 10-15 samtidige brukere. Problemet lå på Apache, som fikk serverloaden opp i omkring 7-8. Oppslag av hostnames i Apache var skrudd av og loggfilene var satt til å roteres hver dag for å forhindre alt for store filer. Siden PHP kjøres gjennom mod_php var dette neste stedet å undersøke. WordPress med et utallig antall plugins resulterer i svært mange PHP-filer som må lastes for hver eneste gang en nettside hentes. Selv et lite Javascript kan kreve mye ressurser dersom dette scriptet har behov for selv bare én enkelt variabel fra databasen. En caching-løsning som cacher HTML-sidene basert på URL og cookies, ala WP-Cache, var ikke noen god løsning, fordi sidene som vises for innloggede brukere ikke bare bestemmes av URL og cookies, men også av variabler hentet fra en database. Memcache ble benyttet for å cache variabler fra databasen for å minke antallet spørringer mot denne, men det hjalp ikke i lengden.</p>
<p>Løsningen på ytelsesproblemet kom med <a href="http://eaccelerator.net/">eAccelerator</a>, en cache-løsning for PHP som cacher de kompilerte PHP-filene, slik at PHP ikke behøver å lese og kompilere alle PHP-filene for hver sidelasting. Andre nettbaserte løsninger som for eksempel benytter Java EE (Enterprise Edition) har en server som hele tiden kjører selv om ingen brukere besøker siden. Fordelen med dette er at alle filer med tilhørende klasser og andre ressurser allerede er lastet inn i minnet på serveren, noe som sparer diskaktivitet og prosessorkraft når brukere besøker siden din.</p>
<p>I dette prosjektet ble versjon 0.9.5 av eAccelerator benyttet. Uten å kjøre nøyaktige benchmarktester så virket denne løsningen betraktelig raskere; sidene lastet raskere i nettleserene og serverloaden er blitt gjennomsnittlig lavere.</p>
<p>eAccelerator finnes ikke i pakkesystemene til Ubuntu eller FreeBSD, så denne må manuelt lastes ned og kompileres. Man trenger dev-pakkene for PHP for å kompilere eAccelerator, da man trenger verktøyet phpize. Dev-pakken på Ubuntu heter php5-dev, eller php4-dev dersom denne versjonen benyttes.<br />
<code><br />
phpize<br />
./configure --enable-eaccelerator \<br />
    --with-php-config=/usr/bin/php-config<br />
make &#038;&#038; make install<br />
</code></p>
<p>Deretter må den aktuelle php.ini-filen som Apache benytter seg av for mod_php oppdateres med følgende innstillinger. Bemerk at kun første linjen er påkrevd. Standard katalog for cache-filene er /tmp/eaccelerator, så denne må opprettes og det må gis skriverettigheter til brukeren som Apache kjører som. På distribusjoner hvor /tmp katalogen slettes ved booting av operativsystemet bør cache_dir settes til en annen katalog, for eksempel /var/cache/eaccelerator. Verdiene i eksempelet nedenfor er hentet fra <a href="http://eaccelerator.net/wiki/InstallFromSource">eAccelerator &#8211; Installing from source</a>.<br />
<code><br />
extension="eaccelerator.so"<br />
eaccelerator.shm_size="16"<br />
eaccelerator.cache_dir="/tmp/eaccelerator"<br />
eaccelerator.enable="1"<br />
eaccelerator.optimizer="1"<br />
eaccelerator.check_mtime="1"<br />
eaccelerator.debug="0"<br />
eaccelerator.filter=""<br />
eaccelerator.shm_max="0"<br />
eaccelerator.shm_ttl="0"<br />
eaccelerator.shm_prune_period="0"<br />
eaccelerator.shm_only="0"<br />
eaccelerator.compress="1"<br />
eaccelerator.compress_level="9"<br />
</code></p>
<p>WordPress har et litt rufsete rykte, blant annet på grunn av at en WordPress-side ikke tåler trykket dersom en artikkel skrevet i en WordPress-blogg havner på forsiden av for eksempel <a href="http://www.digg.com">Digg</a>. Muligens kan en slik cache-løsning være redningen for WordPress, og forsåvidt andre PHP-applikasjoner.</p>
<p><em>Oppdatering 07.03.2007 08:38 CET</em><br />
Et problem med eAccelerator er at instansvariabler deklarert med protected vil få eAccelerator til å krasje dersom en klasse som arver på denne forsøker å aksessere disse protected variablene. Løsningen på dette er å deklarere dem som public. Ikke spesielt god designmetodikk, men det fungerer&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>https://hovenko.no/blog/2007/03/07/eaccelerator-en-php-akselerator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
