<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wikidot="http://www.wikidot.com/rss-namespace">

	<channel>
		<title>Piotr Gabryjeluk dev blog</title>
		<link>http://piotr.gabryjeluk.pl</link>
		<description>Blog, photos and developer notes of Piotr Gabryjeluk, one of Wikidot.com developers.</description>
				<copyright></copyright>
		<lastBuildDate>Sat, 11 Feb 2012 22:28:56 +0000</lastBuildDate>
		
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:lighttpd-xsendfile-problem</guid>
				<title>Lighttpd X-Sendfile Problem</title>
				<link>http://piotr.gabryjeluk.pl/dev:lighttpd-xsendfile-problem</link>
				<description>

&lt;p&gt;It&#039;s not a secret Wikidot uses &lt;a href=&quot;http://lighttpd.net/&quot;&gt;Lighttpd&lt;/a&gt; web server to serve its service. We also use &lt;a href=&quot;http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModFastCGI#X-Sendfile&quot;&gt;X-Sendfile mechanism&lt;/a&gt; to deliver files more intelligently.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Fri, 01 Oct 2010 18:03:35 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>It's not a secret Wikidot uses <a href="http://lighttpd.net/">Lighttpd</a> web server to serve its service. We also use <a href="http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModFastCGI#X-Sendfile">X-Sendfile mechanism</a> to deliver files more intelligently.</p> <div class="content-separator" style="display: none:"></div> <p>Instead of having a PHP process copying file through FastCGI to Lighttpd (which would copy it again to the client) we send a special header to Lighttpd naming the file it should serve to the client. This means PHP processes are terminated quicker, which result in overall better performance.</p> <p>When working on a Wikidot bug (some uploaded files with some special characters in their names are not accessible using links generated by Wikidot itself), I discovered Wikidot also doesn't serve files whose name end with a space.</p> <p>The problem disappeared when I (just for test) disabled X-Sendfile mechanism. Pure PHP has no problems in reading such files and sending them through Lighttpd to browser, so it seemed there's a problem with Lighttpd.</p> <p>Lighttpd v1.4.24 introduced a second X-Sendfile header: X-Sendfile2, which asks Lighttpd to send a chunk of a file (from byte X<sup>th</sup>, to Y<sup>th</sup>), but also a whole file (from byte 0<sup>th</sup> to the last one). The syntax is:</p> <div class="code"> <pre> <code>X-Sendfile2: PATH RANGE</code> </pre></div> <p>Where PATH is URL-encoded file path (PHP's rawurlencode, not the non-standard urlencode), RANGE is X-Y (or &quot;0-&quot; for whole file), so changing:</p> <div class="code"> <pre> <code>header(&quot;X-Sendfile: &quot; . $path);</code> </pre></div> <p>to</p> <div class="code"> <pre> <code>header(&quot;X-Sendfile2: &quot; . rawurlencode($path) . &quot; 0-&quot;);</code> </pre></div> <p>fixes the problem.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:yaml-and-php</guid>
				<title>YAML and PHP</title>
				<link>http://piotr.gabryjeluk.pl/dev:yaml-and-php</link>
				<description>

&lt;p&gt;There are 3 main YAML implementations for PHP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Syck (native C library bindings to PHP)&lt;/li&gt;
&lt;li&gt;Symphony YAML (pure PHP)&lt;/li&gt;
&lt;li&gt;Spyc (pure PHP again)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the comparison.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 30 Jul 2009 19:03:36 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>There are 3 main YAML implementations for PHP:</p> <ul> <li>Syck (native C library bindings to PHP)</li> <li>Symphony YAML (pure PHP)</li> <li>Spyc (pure PHP again)</li> </ul> <p>This is the comparison.</p> <div class="content-separator" style="display: none:"></div> <h1><span>What the hell is YAML</span></h1> <p>Have you heard about XML or JSON? YAML is similarly to JSON and XML a way to store (read and write) structured data like arrays (a.k.a. lists), dictionaries (a.k.a. hash maps) and atomic values like strings and numbers. The structures can be nested, to form a definition of near-real-life objects, for example:</p> <div class="code"> <pre> <code>--- Piotr Gabryjeluk: company: Wikidot Inc. university: Nicolaus Copernicus University, Toruń, Poland lives_in: Toruń, Poland hobbies: - basketball - playing the guitar</code> </pre></div> <p>Which translates to PHP:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-var">$data</span><span class="hl-code"> = </span><span class="hl-reserved">array</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Piotr Gabryjeluk</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-reserved">array</span><span class="hl-brackets">(</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-string">company</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">Wikidot Inc.</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">university</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">Nicolaus Copernicus University, Toruń, Poland</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">lives_in</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">Toruń, Poland</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">hobbies</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-reserved">array</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">basketball</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">playing the guitar</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">))</span><span class="hl-code">;</span> </pre></div> </div> <p>So you see YAML is quite nice even when you need to write it yourself.</p> <p>YAML has its specification (see <a href="http://yaml.org">http://yaml.org</a>), so once we have standard YAML parser and standard YAML dumper we can send arrays from one machine to another and the result should be the same array as was sent.</p> <h1><span>PHP</span></h1> <p>So let's see what are the choices if you want to play with YAML in PHP.</p> <h2><span>Syck</span></h2> <p>This is the fastest and the most complete YAML dumper and loader library available. This is binding to C library and this is available in PEAR. It is also available as regular package in Ubuntu repository, so install it by simple:</p> <div class="code"> <pre> <code>aptitude install php5-syck</code> </pre></div> <p>In some shared hosting environment this could be a problem, so you need a pure PHP solution.</p> <h2><span>Spyc</span></h2> <p>This was the first PHP YAML implementation I saw. It is both dumper and loader and it seemed to work fine, but then I found some bugs, that stopped me from using it as the base and only YAML loader and dumper for Wikidot.</p> <p>This one has really nice thing, which is nice when you want your users to enter YAML to define things (like we do for forms). It is quite forgiving when it comes to the syntax and ignores things that don't fit and still parses the rest.</p> <p>Unfortunately as I stated before Spyc dumper so, when you first dump an array and then load it with Spyc you get something different (for example multiple new-lines are treated as one). Not good. Also as a loader it does not fully understand the full YAML specification (which is quite huge BTW).</p> <h2><span>Symphony YAML</span></h2> <p>This one is pure-PHP as well, so you don't need special rights, to use it on a PHP-enabled machine.</p> <p>It's loader does not understand full YAML specification, so for example you can't load documents dumped by Syck. Dumper is good.</p> <h1><span>Summary</span></h1> <table class="wiki-content-table"> <tr> <th></th> <th>Syck</th> <th>Spyc</th> <th>Symphony YAML</th> </tr> <tr> <td>type of library</td> <td>PHP extension</td> <td><strong>pure PHP library</strong></td> <td><strong>pure PHP library</strong></td> </tr> <tr> <td>speed</td> <td><strong>fast</strong></td> <td>slow</td> <td>slow</td> </tr> <tr> <td>loader: YAML support</td> <td><strong>full</strong></td> <td>bad</td> <td>not bad</td> </tr> <tr> <td>loader: if YAML is corrupted</td> <td>exception</td> <td><strong>tries to do its best to load the rest</strong></td> <td>exception</td> </tr> <tr> <td>dumper: YAML human-readable</td> <td>more-or-less</td> <td><strong>yes</strong></td> <td>more-or-less if set properly</td> </tr> <tr> <td>dumper: YAML conforms to spec</td> <td><strong>yes</strong></td> <td>no</td> <td><strong>yes</strong></td> </tr> <tr> <td>loads Syck's dumper output correctly</td> <td><strong>yes</strong></td> <td>no</td> <td>no</td> </tr> <tr> <td>loads Symphony's dumper output correctly</td> <td><strong>yes</strong></td> <td>no</td> <td><strong>yes</strong></td> </tr> </table> <h2><span>Verdict: loader</span></h2> <p>Syck is the winner in loading YAML. If you cannot use Syck, use Symphony YAML. If you need to parse user input (which should be human readable/writable similar to YAML), use Spyc.</p> <p>Actually, this is nice combination for loading:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">try</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">// if syck is available use it</span><span class="hl-code"> </span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">extension_loaded</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">syck</span><span class="hl-quotes">'</span><span class="hl-brackets">))</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-identifier">syck_load</span><span class="hl-brackets">(</span><span class="hl-var">$string</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-comment">// if not, use the symfony YAML parser</span><span class="hl-code"> </span><span class="hl-var">$yaml</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">sfYamlParser</span><span class="hl-brackets">()</span><span class="hl-code">; </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-var">$yaml</span><span class="hl-code">-&gt;</span><span class="hl-identifier">parse</span><span class="hl-brackets">(</span><span class="hl-var">$string</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-reserved">catch</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">Exception</span><span class="hl-code"> </span><span class="hl-var">$e</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">// if YAML document is not correct,</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-identifier">Spyc</span><span class="hl-code">::</span><span class="hl-identifier">YAMLLoadString</span><span class="hl-brackets">(</span><span class="hl-var">$string</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span> </pre></div> </div> <p>This way, you have the fastest library used if possible, then the best pure-PHP, and if it fails in a way, that document was badly written (by human being for example), you fall-back to Spyc.</p> <h2><span>Verdict: dumper</span></h2> <p>In my opinion Symphony YAML dumper is the best from the three in terms of usability, portability and interoperability, because its output can be read by both itself and Spyc.</p> <p>However, if you dump YAML often, use (hell faster) Syck for both loading and dumping. The generated YAML won't be readable by Symphony YAML or Spyc, but this is because they don't follow the specification (so not Syck's problem in fact).</p> <p>Also note, that any valid JSON dumper output is readable by standard YAML 1.2 loaders, because JSON is a subset of YAML 1.2. So if using for data exchange (and not for talking to human) any fast JSON dumper can be used.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:php-as-fastcgi-backend</guid>
				<title>PHP as FastCGI backend and Lighttpd</title>
				<link>http://piotr.gabryjeluk.pl/dev:php-as-fastcgi-backend</link>
				<description>

&lt;h1&gt;&lt;span&gt;Wikidot + Lighttpd + PHP5&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;At Wikidot we use PHP5 as FastCGI backend to Lighttpd light-and-fast webserver. It works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;there are a few hundreds of php5-cgi processes (name is cgi, but they also support FastCGI mode) running and waiting to be used&lt;/li&gt;
&lt;li&gt;lighttpd (only one needed!) process manages the network connections to all the clients and once the request is ready serves a static file or forwards the request to one of PHP backends processes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 15 Jun 2009 20:59:29 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <h1><span>Wikidot + Lighttpd + PHP5</span></h1> <p>At Wikidot we use PHP5 as FastCGI backend to Lighttpd light-and-fast webserver. It works like this:</p> <ul> <li>there are a few hundreds of php5-cgi processes (name is cgi, but they also support FastCGI mode) running and waiting to be used</li> <li>lighttpd (only one needed!) process manages the network connections to all the clients and once the request is ready serves a static file or forwards the request to one of PHP backends processes.</li> </ul> <div class="content-separator" style="display: none:"></div> <p>We used to use internal Lighttpd FastCGI process manager, meaning the lighttpd processes actually used to start the PHPs.</p> <h1><span>Problems</span></h1> <p>We encountered some known problems of 500 (server side) errors appearing after some random time, especially under a high traffic. The typical message appearing at the Lighttpd's error.log was:</p> <div class="code"> <pre> <code>&lt;some date&gt;: (mod_fastcgi.c.2494) unexpected end-of-file (perhaps the fastcgi process died): pid: ...</code> </pre></div> <p>There are plenty of reports on this in both <a href="http://forum.lighttpd.net/topic/93190">Lighttpd</a>'s and <a href="http://bugs.php.net/bug.php?id=43295">PHP</a>'s <a href="http://forum.lighttpd.net/topic/93190">forums</a>, <a href="http://pecl.php.net/bugs/bug.php?id=12608">bug</a> <a href="http://redmine.lighttpd.net/issues/1466">trackers</a> and even <a href="http://www.rooftopsolutions.nl/article/201">some</a> <a href="http://jcj.net/?p=24">blogs</a>.</p> <h1><span>Workarounds</span></h1> <p>We managed to write some hacky scripts that detected the situation and restarted the backends when needed. The reaction was so quick, that almost no-one noticed the error, but damn, this is not how WE solve problems.</p> <h1><span>A blind try</span></h1> <p>We decided to give spawn-fcgi a shot. What is it? It is a program that spawns FastCGI backends (independently from Lighttpd server). Why trying it? I've read somewhere, that it works more reliably than the internal Lighttpd spawner. What's interesting is that this program comes from lighttpd package, so we're in family anyway. It's mainly intended to run the FastCGI backends from different user than the webserver user or to run them on different machine(s) than the webserver machine. This can be used naturally for some smart load-balancing.</p> <p>The only problem of this solution we encountered was internal limit of number of processes to spawn by a single process which was 256 (hardcoded, fixed in next versions). But at the same time, we decided to build a few FastCGI bridges (each spawning ~200 PHPs) anyway so that was no longer a problem for us.</p> <p>What was quite surprising (but honestly, I deeply believed in this), our problems with 500 server errors and PHP disappeared. This configuration works for about 2 weeks now with absolutely no hacky scripts involved and no restarting needed. Cool.</p> <h1><span>Why I wrote this</span></h1> <p>I wrote this short note just for the record and to let other people know, that using spawn-fcgi instead of the internal Lighttpd's FastCGI spawner might solve their problems with PHP (FastCGI) and 500 internal server errors.</p> <p>Hope this helps someone.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:o-zend-framework</guid>
				<title>O Zend Framework</title>
				<link>http://piotr.gabryjeluk.pl/dev:o-zend-framework</link>
				<description>

&lt;p&gt;Pewien czas temu, mówiłem ciepłe słowa o Zend Framework. Okazuje się, że nie jest tak różowo jak się wydaje. A wyrażeniem kluczowym jest tutaj:&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 11 Mar 2009 19:34:06 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>Pewien czas temu, mówiłem ciepłe słowa o Zend Framework. Okazuje się, że nie jest tak różowo jak się wydaje. A wyrażeniem kluczowym jest tutaj:</p> <div class="content-separator" style="display: none:"></div> <div style="text-align: center;"> <p><span style="font-size:large;"><strong>64 bit</strong></span></p> </div> <p>Na 64 bitowym systemie, z Zend Framework jest wiele problemów. Wymienię ich kilka:</p> <h1><span>Zend_Search_Lucene</span></h1> <p>Już taki prosty kod, uruchamiany na 64-bitowym systemie powoduje nieskończone pętle i przekraczanie limitu pamięci:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">require_once</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Zend/Search/Lucene.php</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-var">$index</span><span class="hl-code"> = </span><span class="hl-identifier">Zend_Search_Lucene</span><span class="hl-code">::</span><span class="hl-identifier">open</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">/path/to/index</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span> </pre></div> </div> <p>Oczywiście pierwsze co robimy, żeby korzystać z indeksu, to go otwieramy, więc ten moduł (Zend_Search_Lucene) staje się zupełnie niezdatny do użytku.</p> <p>Co ciekawe, <a href="http://framework.zend.com/issues/browse/ZF-4071">problem jest zgłoszony</a> na bug-trackerze ZF. Doszedłem co trzeba zrobić, żeby rozwiązać problem, wrzuciłem na bug-trackera gotowego (mniej lub bardziej) diffa, ale nikt się nie przejął ani błędem, ani rozwiązaniem.</p> <h1><span>Zend_Db</span></h1> <p>Jednym z ważniejszych elementów zawartych w Zend Framework, jest warstwa dostępu do bazy danych. Niestety na 64 bitowym systemie, framework ma jakieś problemy z ograniczaniem wyników przy użyciu metody limit. Nakazanie wyświetlenia rekordów począwszy od rekordu 0, wygenerowało mi zapytanie, które kończyło się na:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-reserved">LIMIT</span><span class="hl-code"> </span><span class="hl-number">98382101</span><span class="hl-code">, </span><span class="hl-number">20</span><span class="hl-code">;</span> </pre></div> </div> <p>Powinno być:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-reserved">LIMIT</span><span class="hl-code"> </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-number">20</span><span class="hl-code">;</span> </pre></div> </div> <p>Głupia sprawa. Może to poprawili w nowszej wersji, może nie. Nie zgłębiałem tego.</p> <h1><span>Zend_XmlRpc_Server</span></h1> <p>Ostatnio pracując nad <a href="http://piotr.gabryjeluk.pl/dev:wikidot-api">Wikidot API</a> natrafiłem na paskudny i ukryty błąd w komponencie serwera XML-RPC Zend Framework.</p> <p>Wszystko niby działa, ale wołanie przez klienta XML-RPC funkcji <tt>system.methodHelp</tt>, czy <tt>system.methodSignature</tt> kończy się błędem niedopasowania rządanej metody to sygnatur znanych metod. Na 32 bitach wszystko działa.</p> <h1><span>Podsumowanie</span></h1> <p>Zend Framework może się wydawać fajny (mi się wydawał), ale uważajcie mocno przy przenoszeniu kodu z 32 bitów (np. na laptopie) na 64 bity (np. na serwer). Jest SPORO bugów w tym naprawdę dokuczliwe, związane z Zend_Db.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:working-on-wdlite</guid>
				<title>Working On wdLite</title>
				<link>http://piotr.gabryjeluk.pl/dev:working-on-wdlite</link>
				<description>

&lt;p&gt;A few days ago I started working on wdLite &amp;#8212; a lite version of Wikidot.&lt;/p&gt;
&lt;p&gt;The primary aim of this project is to make installation dead simple and server requirements really small.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 03 Feb 2009 00:54:15 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>A few days ago I started working on wdLite &#8212; a lite version of Wikidot.</p> <p>The primary aim of this project is to make installation dead simple and server requirements really small.</p> <div class="content-separator" style="display: none:"></div> <h1><span>Server requirements</span></h1> <p>wdLite should be installable on:</p> <ul> <li>Apache with PHP5 (no safe mode or other limitations) and PostgreSQL on Linux boxes</li> </ul> <p>PHP and PostgreSQL should be already configured to work with each other. You should have a PostgreSQL database and &quot;user/password/database&quot;-based access to it. Wikidot will create tables, but won't create a database. You should either create it as root or have root created it for you before (this process might be automatic on webhosting services with PHP/PostgreSQL).</p> <p>This configuration should include a whole bunch of virtual hosting providers.</p> <h1><span>Installation</span></h1> <p>The installation process should be no harder than this:</p> <ul> <li>Get a zip or checkout the newest version from repository</li> <li>Upload the directory to the server</li> <li>Adjust directory permissions</li> <li>Go to install.php script with your browser</li> <li>Supply mail and PostgreSQL credentials</li> <li>Choose your wiki name and create users</li> <li>Enjoy your new wiki</li> </ul> <h1><span>What are the differences between &quot;full&quot; Wikidot installation and wdLite</span></h1> <h2><span>Limitations</span></h2> <ul> <li>only one wiki</li> <li>no page revision diffs</li> <li>more limited page size</li> <li>lower security (especially for IE users)</li> <li>works only with Apache</li> <li>some features disabled or non-working</li> <li>memcached disabled</li> <li>karma disabled</li> <li>notifications disabled</li> </ul> <h2><span>Better than full version, because</span></h2> <ul> <li>works with Apache</li> <li>works on any HTTP port (not only 80)</li> <li>works within any directory (also in user directory accessible like <a href="http://myserver.com/~quake/something/really/deep/wikidot">http://myserver.com/~quake/something/really/deep/wikidot</a>)</li> <li>easier installation with a web interface</li> <li>no root-access needed</li> <li>works well with GMail to send mails from the service</li> <li>easily installable on Ubuntu</li> <li>the easiest method to start developing with Wikidot</li> <li>no need to manually compile additional software</li> </ul> <h1><span>Current work progress</span></h1> <p>I'm about to pre-release this software, to let you test it.</p> <p>I have to:</p> <ul> <li>create a list of things that need to work before a final 1.0 release.</li> <li>redirect / to /?/</li> <li>create install.php</li> </ul> <p>Things that work already:</p> <ul> <li>logging in/out</li> <li>displaying pages</li> <li>editing pages</li> <li>saving pages</li> <li>some basic modules</li> <li>uploading and displaying files</li> <li>navigation (links are rewritten from absolute to relative)</li> </ul> <h1><span>How does it work</span></h1> <p>The wdLite is based on Wikidot OpenSource. It contains wikidot, index.php and a bunch of helpers scripts. The index.php file is a hacky PHP script that</p> <ul> <li>converts URL-s like <a href="http://some.server.com/some/url/?/front:page">http://some.server.com/some/url/?/front:page</a> to <a href="http://www.some.server.com/front:page">http://www.some.server.com/front:page</a></li> <li>tricks Wikidot software to think that the Wikidot domain is some.server.com and the main wiki is www.some.server.com</li> <li>sets a bunch of system variables Wikidot relies on, like $_SERVER['REQUEST_URI'], $_SERVER['QUERY_STRING']</li> <li>runs a proper one from Wikidot scripts</li> <li>&#8230; or serves (more like redirects to) a static file</li> <li>catches the script output</li> <li>runs some transformation on caught output (like converting the links from <a href="http://www.some-server.com/some:other-page">http://www.some-server.com/some:other-page</a> to ?/some:other-page)</li> <li>sends the data back to browser</li> </ul> <p><strong>WARNING, ACHTUNG</strong><br /> The script is more a dirty hack than a version of Wikidot, but this is intentional. We don't want to mantain to many versions of Wikidot. Having this dirty script &quot;only using without modyfing&quot; Wikidot software makes it quite independent from changes in Wikidot. This means the same wdLite script will work for a newer version of Wikidot (=less maintaining work).<br /> <strong>WARNING, ACHTUNG</strong></p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:wikidot-api</guid>
				<title>Wikidot API</title>
				<link>http://piotr.gabryjeluk.pl/dev:wikidot-api</link>
				<description>

&lt;p&gt;A few days ago I started working on Wikidot &lt;a href=&quot;http://en.wikipedia.org/wiki/API&quot;  &gt;API&lt;/a&gt;. The API will be a standardized way to access the Wikidot.com service in a programmable way (i.e. not using a browser) to retrieve, create and update information stored on Wikidot, including site browsing, page editing and commenting.&lt;/p&gt;
&lt;p&gt;In simple words this will allow people to write applications that connect to Wikidot.com and perform some actions for the user that runs the application.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 22 Jan 2009 18:57:07 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>A few days ago I started working on Wikidot <a href="http://en.wikipedia.org/wiki/API" >API</a>. The API will be a standardized way to access the Wikidot.com service in a programmable way (i.e. not using a browser) to retrieve, create and update information stored on Wikidot, including site browsing, page editing and commenting.</p> <p>In simple words this will allow people to write applications that connect to Wikidot.com and perform some actions for the user that runs the application.</p> <div class="content-separator" style="display: none:"></div> <p>Technically, the Wikidot.com API is an <a href="http://en.wikipedia.org/wiki/XML-RPC" >XML-RPC</a> service exporting methods from a few especially designed classes.</p> <p>To connect to an XML-RPC service, you must know its endpoint, which is a regular URL (http:// or https://) address. We decided to use <a href="http://en.wikipedia.org/wiki/HTTPS" >HTTPS</a> to secure the channel from the very start.</p> <p>The operations we are going to support are:</p> <h2><span>Browse</span></h2> <ul> <li>site.categories</li> <li>site.pages</li> <li>page.get</li> </ul> <p>Above ones are already implemented. Using the API calls you get retrieve almost all data you stored on the Wikidot.com sites!</p> <h2><span>Modify</span></h2> <ul> <li>page.save</li> </ul> <p>This will be the basic method to update the content on your site. We plan several other methods, but this is the one that is the most important.</p> <h2><span>Comments</span></h2> <ul> <li>page.comments</li> <li>page.comment</li> </ul> <p>They will be used to get and post comments on a given page. Using <tt>reply_to</tt> parameter, there is a possibility to reply to a particular comment.</p> <h2><span>Forum</span></h2> <ul> <li>forum.groups</li> <li>forum.categories</li> <li>forum.threads</li> <li>forum.post</li> </ul> <p>This bunch of methods are going to give you full access to the forums you have started on Wikidot.</p> <h1><span>How to use the API</span></h1> <p>We haven't yet enabled the API access to the main Wikidot.com server, but testing the API with Python XML-RPC library is as easy as this:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-code">&gt;&gt;&gt; </span><span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">xmlrpclib</span><span class="hl-code"> </span><span class="hl-reserved">import</span><span class="hl-code"> </span><span class="hl-identifier">ServerProxy</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-identifier">s</span><span class="hl-code"> = </span><span class="hl-identifier">ServerProxy</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">SOME-URL</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-identifier">s</span><span class="hl-code">.</span><span class="hl-identifier">system</span><span class="hl-code">.</span><span class="hl-identifier">listMethods</span><span class="hl-brackets">()</span><span class="hl-code"> </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">system.listMethods</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">system.methodHelp</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">system.methodSignature</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">system.multicall</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">site.pages</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">site.categories</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">page.get</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-reserved">print</span><span class="hl-code"> </span><span class="hl-identifier">s</span><span class="hl-code">.</span><span class="hl-identifier">system</span><span class="hl-code">.</span><span class="hl-identifier">methodHelp</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">site.pages</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-identifier">Get</span><span class="hl-code"> </span><span class="hl-identifier">pages</span><span class="hl-code"> </span><span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">a</span><span class="hl-code"> </span><span class="hl-identifier">site</span><span class="hl-code"> </span><span class="hl-identifier">Argument</span><span class="hl-code"> </span><span class="hl-identifier">array</span><span class="hl-code"> </span><span class="hl-identifier">keys</span><span class="hl-code">: </span><span class="hl-identifier">site</span><span class="hl-code">: </span><span class="hl-identifier">site</span><span class="hl-code"> </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-identifier">get</span><span class="hl-code"> </span><span class="hl-identifier">pages</span><span class="hl-code"> </span><span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">category</span><span class="hl-code">: </span><span class="hl-identifier">category</span><span class="hl-code"> </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-identifier">get</span><span class="hl-code"> </span><span class="hl-identifier">pages</span><span class="hl-code"> </span><span class="hl-identifier">from</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">optional</span><span class="hl-brackets">)</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-identifier">s</span><span class="hl-code">.</span><span class="hl-identifier">site</span><span class="hl-code">.</span><span class="hl-identifier">categories</span><span class="hl-brackets">(</span><span class="hl-code">{</span><span class="hl-quotes">'</span><span class="hl-string">site</span><span class="hl-quotes">'</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">gamemaker</span><span class="hl-quotes">'</span><span class="hl-code">}</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">project</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">rpg</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">_default</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">action</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">admin</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">badge</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">beginner</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">contests</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">error</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">event</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">example</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">forum</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">gamemaker</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">gml</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">gmlcode</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">gmupload</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">help</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">ide</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">include</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">mamber</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">member</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">nav</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">portal</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">resource</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">search</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">system</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">talk</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">template</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">tutorial</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">video-tutorial</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">wiki</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">challenge</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">howto</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">recent-changes</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">scratch-pad</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">helpdesk</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">helprequest</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">default</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">testimonial</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">testimonials</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-brackets">[</span><span class="hl-identifier">p</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">name</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code"> </span><span class="hl-reserved">for</span><span class="hl-code"> </span><span class="hl-identifier">p</span><span class="hl-code"> </span><span class="hl-reserved">in</span><span class="hl-code"> </span><span class="hl-identifier">s</span><span class="hl-code">.</span><span class="hl-identifier">site</span><span class="hl-code">.</span><span class="hl-identifier">pages</span><span class="hl-brackets">(</span><span class="hl-code">{</span><span class="hl-quotes">'</span><span class="hl-string">site</span><span class="hl-quotes">'</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">gamemaker</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">category</span><span class="hl-quotes">'</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">badge</span><span class="hl-quotes">'</span><span class="hl-code">}</span><span class="hl-brackets">)]</span><span class="hl-code"> </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">cool</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">flux</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">c-team</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">gml</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">member</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">madman</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">not-a-noob</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">f-madman</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">start</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">break-it</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code"> &gt;&gt;&gt; </span><span class="hl-reserved">print</span><span class="hl-code"> </span><span class="hl-identifier">s</span><span class="hl-code">.</span><span class="hl-identifier">page</span><span class="hl-code">.</span><span class="hl-identifier">get</span><span class="hl-brackets">(</span><span class="hl-code">{</span><span class="hl-quotes">'</span><span class="hl-string">site</span><span class="hl-quotes">'</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">gamemaker</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">page</span><span class="hl-quotes">'</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">badge:cool</span><span class="hl-quotes">'</span><span class="hl-code">}</span><span class="hl-brackets">)[</span><span class="hl-quotes">'</span><span class="hl-string">source</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">table</span><span class="hl-code"> </span><span class="hl-identifier">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">width:98%;margin-right:auto;margin-left:auto;margin-bottom:1%;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]][[</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-identifier">cell</span><span class="hl-code"> </span><span class="hl-identifier">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">width:360px;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">div</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">error-block</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-identifier">Included</span><span class="hl-code"> </span><span class="hl-identifier">page</span><span class="hl-code"> </span><span class="hl-quotes">&quot;</span><span class="hl-string">include:cool-badge</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">does</span><span class="hl-code"> </span><span class="hl-reserved">not</span><span class="hl-code"> </span><span class="hl-identifier">exist</span><span class="hl-code"> </span><span class="hl-brackets">([</span><span class="hl-code">/</span><span class="hl-identifier">include</span><span class="hl-code">:</span><span class="hl-identifier">cool</span><span class="hl-code">-</span><span class="hl-identifier">badge</span><span class="hl-code">/</span><span class="hl-identifier">edit</span><span class="hl-code">/</span><span class="hl-identifier">true</span><span class="hl-code"> </span><span class="hl-identifier">create</span><span class="hl-code"> </span><span class="hl-identifier">it</span><span class="hl-code"> </span><span class="hl-identifier">now</span><span class="hl-brackets">])</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">div</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-identifier">The</span><span class="hl-code"> </span><span class="hl-identifier">Cool</span><span class="hl-code"> </span><span class="hl-identifier">Badge</span><span class="hl-code"> </span><span class="hl-reserved">is</span><span class="hl-code"> </span><span class="hl-identifier">given</span><span class="hl-code"> </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-identifier">people</span><span class="hl-code"> </span><span class="hl-identifier">who</span><span class="hl-code"> </span><span class="hl-identifier">make</span><span class="hl-code"> </span><span class="hl-identifier">something</span><span class="hl-code"> </span><span class="hl-identifier">really</span><span class="hl-code"> </span><span class="hl-identifier">cool</span><span class="hl-code">. </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">cell</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">cell</span><span class="hl-code"> </span><span class="hl-identifier">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">vertical-align:top;border:1px solid #ddd;padding:1%;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]]</span><span class="hl-code"> +++ </span><span class="hl-identifier">Display</span><span class="hl-code"> </span><span class="hl-identifier">Code</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">table</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">code</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]][[</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-identifier">cell</span><span class="hl-brackets">]]</span><span class="hl-code"> @@</span><span class="hl-brackets">[[</span><span class="hl-identifier">include</span><span class="hl-code"> </span><span class="hl-identifier">include</span><span class="hl-code">:</span><span class="hl-identifier">cool</span><span class="hl-code">-</span><span class="hl-identifier">badge</span><span class="hl-code"> </span><span class="hl-identifier">member</span><span class="hl-code">=</span><span class="hl-identifier">member</span><span class="hl-code"> </span><span class="hl-identifier">name</span><span class="hl-brackets">]]</span><span class="hl-code">@@ </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">cell</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">table</span><span class="hl-brackets">]]</span><span class="hl-code"> +++ </span><span class="hl-identifier">Tag</span><span class="hl-code"> {{</span><span class="hl-identifier">cool</span><span class="hl-code">-</span><span class="hl-identifier">badge</span><span class="hl-code">}} </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">cell</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">table</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">table</span><span class="hl-code"> </span><span class="hl-identifier">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">border:1px solid #ddd;padding:1%;margin-right:auto;margin-left:auto;margin-bottom:1%;width:98%;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]][[</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-identifier">cell</span><span class="hl-brackets">]]</span><span class="hl-code"> ++ </span><span class="hl-identifier">Earn</span><span class="hl-code"> </span><span class="hl-identifier">It</span><span class="hl-code"> * </span><span class="hl-identifier">Program</span><span class="hl-code"> </span><span class="hl-identifier">something</span><span class="hl-code"> </span><span class="hl-identifier">really</span><span class="hl-code"> </span><span class="hl-identifier">cool</span><span class="hl-code"> </span><span class="hl-identifier">using</span><span class="hl-code"> </span><span class="hl-identifier">gml</span><span class="hl-code"> * </span><span class="hl-identifier">Make</span><span class="hl-code"> </span><span class="hl-identifier">a</span><span class="hl-code"> </span><span class="hl-identifier">really</span><span class="hl-code"> </span><span class="hl-identifier">cool</span><span class="hl-code"> </span><span class="hl-identifier">game</span><span class="hl-code"> +++ </span><span class="hl-identifier">Tips</span><span class="hl-code"> * </span><span class="hl-identifier">Make</span><span class="hl-code"> </span><span class="hl-identifier">sure</span><span class="hl-code"> </span><span class="hl-identifier">you</span><span class="hl-code"> </span><span class="hl-identifier">post</span><span class="hl-code"> </span><span class="hl-identifier">your</span><span class="hl-code"> </span><span class="hl-identifier">examples</span><span class="hl-code"> </span><span class="hl-reserved">and</span><span class="hl-code"> </span><span class="hl-identifier">games</span><span class="hl-code"> </span><span class="hl-identifier">on</span><span class="hl-code"> </span><span class="hl-identifier">the</span><span class="hl-code"> </span><span class="hl-brackets">[[[</span><span class="hl-identifier">forum</span><span class="hl-code">:</span><span class="hl-identifier">start</span><span class="hl-code">|</span><span class="hl-identifier">forum</span><span class="hl-brackets">]]]</span><span class="hl-code">. </span><span class="hl-identifier">Otherwise</span><span class="hl-code"> </span><span class="hl-identifier">no</span><span class="hl-code"> </span><span class="hl-identifier">one</span><span class="hl-code"> </span><span class="hl-identifier">can</span><span class="hl-code"> </span><span class="hl-identifier">see</span><span class="hl-code"> </span><span class="hl-identifier">it</span><span class="hl-code"> </span><span class="hl-reserved">and</span><span class="hl-code"> </span><span class="hl-identifier">nominate</span><span class="hl-code"> </span><span class="hl-identifier">you</span><span class="hl-code"> </span><span class="hl-reserved">for</span><span class="hl-code"> </span><span class="hl-identifier">the</span><span class="hl-code"> </span><span class="hl-identifier">cool</span><span class="hl-code"> </span><span class="hl-identifier">badge</span><span class="hl-code">. </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">cell</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">table</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">table</span><span class="hl-code"> </span><span class="hl-identifier">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">border:1px solid #ddd;padding:1%;margin-right:auto;margin-left:auto; width:98%;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]][[</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-identifier">cell</span><span class="hl-brackets">]]</span><span class="hl-code"> ++ </span><span class="hl-identifier">Members</span><span class="hl-code"> </span><span class="hl-identifier">Who</span><span class="hl-code"> </span><span class="hl-identifier">Have</span><span class="hl-code"> </span><span class="hl-identifier">Earned</span><span class="hl-code"> </span><span class="hl-identifier">the</span><span class="hl-code"> </span><span class="hl-identifier">Cool</span><span class="hl-code"> </span><span class="hl-identifier">Badge</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-identifier">module</span><span class="hl-code"> </span><span class="hl-identifier">ListPages</span><span class="hl-code"> </span><span class="hl-identifier">category</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">member</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">order</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">titleAsc</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">tag</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">cool-badge</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">perPage</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">100</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">separate</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">false</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]]</span><span class="hl-code"> * %%</span><span class="hl-identifier">linked_title</span><span class="hl-code">%% </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">module</span><span class="hl-brackets">]]</span><span class="hl-code"> </span><span class="hl-brackets">[[</span><span class="hl-code">/</span><span class="hl-identifier">cell</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">row</span><span class="hl-brackets">]][[</span><span class="hl-code">/</span><span class="hl-identifier">table</span><span class="hl-brackets">]]</span><span class="hl-code"> &gt;&gt;&gt;</span> </pre></div> </div> <p>A few words of explanation:</p> <ul> <li>first we import ServerProxy class from XML-RPC library,</li> <li>then we construct the ServerProxy object s supplying the endpoint URL (SOME-URL in this case, as we don't have yet decided what the URL is going to be)</li> <li>we can see a list of methods by calling <tt>system.listMethods</tt> on the ServerProxy object</li> <li>we get a help message for a method by calling <tt>system.methodHelp</tt></li> <li>then we get categories of site gamemaker (yeah, it's a part of the wikicomplete.info)</li> <li>then we call <tt>site.pages</tt> method (specifying site and category parameters), but instead of displaying the whole list of structures that describe pages, we only display their names</li> <li>calling <tt>page.get</tt> returns an array with the information about a page, including: <ul> <li>wiki source, array key: source</li> <li>generated HTML, array key: html</li> <li>array with various meta-data, array key: meta</li> </ul> </li> <li>we call <tt>page.get</tt> passing as the argument array that specifies site and page name, get the page object, but displays only what's stored under the <tt>source</tt> array key</li> </ul> <p>As you see playing with this is really easy as is browsing the available methods and using them.</p> <h1><span>Why XML-RPC</span></h1> <p>We've chosen this protocol because it is an easy way to develop both server and client in almost any programming language. Also it gives some flexibility in passed arguments and return values.</p> <p>We use <tt>struct</tt> XML-RPC type as the argument and return value type, which is mapped to associative array or dictionary in client (and server) libraries. Each API method gets a bunch of required and optional parameters, that are basically values stored in the struct passed to API methods.</p> <p>For example <tt>site.pages</tt> gets a struct with the following keys:</p> <ul> <li>site (site name to get pages from) &#8212; required</li> <li>category (category to get pages from) &#8212; optional</li> </ul> <p>This means, you have to create an associative array (when using PHP) or a dictionary (using Python) and pass it as the method argument:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-code"># PHP $pages = $server-&gt;site-&gt;pages(array(&quot;site&quot; =&gt; &quot;my-site&quot;, &quot;category&quot; =&gt; &quot;my-category&quot;));</span> </pre></div> </div> <div class="code"> <div class="hl-main"> <pre> <span class="hl-comment"># Python</span><span class="hl-code"> </span><span class="hl-identifier">pages</span><span class="hl-code"> = </span><span class="hl-identifier">server</span><span class="hl-code">.</span><span class="hl-identifier">site</span><span class="hl-code">.</span><span class="hl-identifier">pages</span><span class="hl-brackets">(</span><span class="hl-code">{</span><span class="hl-quotes">&quot;</span><span class="hl-string">site</span><span class="hl-quotes">&quot;</span><span class="hl-code">: </span><span class="hl-quotes">&quot;</span><span class="hl-string">my-site</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">category</span><span class="hl-quotes">&quot;</span><span class="hl-code">: </span><span class="hl-quotes">&quot;</span><span class="hl-string">my-category</span><span class="hl-quotes">&quot;</span><span class="hl-code">}</span><span class="hl-brackets">)</span> </pre></div> </div> <p>Using other programming languages, you'll end with something similar. You can almost always create the array/dictionary in-place, so having this convention is not a big deal.</p> <h1><span>Applications</span></h1> <p>I'm working on a filesystem based access to Wikidot site (using <a href="http://en.wikipedia.org/wiki/FUSE" >FUSE</a> and Python).</p> <p>We plan having a Wikidot application for iPhone.</p> <p>A save-it-directly-on-wikidot plugin would be a nice thing for various text editors (and probably other applications).</p> <p>And probably there are billions of other ways to use this API we're not even aware of. If you have any, feel free to leave a comment.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:bridging-python-and-php</guid>
				<title>Bridging Python And PHP</title>
				<link>http://piotr.gabryjeluk.pl/dev:bridging-python-and-php</link>
				<description>

&lt;p&gt;Imagine you have a PHP-based application (like Wikidot). Now, you want to extend it using Python. Through all ways to do it, I&#039;ll show you how to achieve this using XML-RPC protocol.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Sun, 11 Jan 2009 10:48:16 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>Imagine you have a PHP-based application (like Wikidot). Now, you want to extend it using Python. Through all ways to do it, I'll show you how to achieve this using XML-RPC protocol.</p> <div class="content-separator" style="display: none:"></div> <h1><span>Background</span></h1> <p><a href="http://www.xmlrpc.com/">XML-RPC</a> is a client-server protocol for remote procedure call.</p> <p>On server this works like getting a bunch of functions from your application and exporting it with HTTP.</p> <p>On client this works like connecting to a XML-RPC server, finding out what function it delivers and constructing a so called server proxy &#8212; an object having a method for every function exported by an XML-RPC server.</p> <p>Calling the methods of the server proxy connects to the server using HTTP, passes arguments and transport the result back to the client. So basically this works AS you have a remote located object locally available.</p> <p>The data encoding between client and server is defined in XML-RPC specification and is a language based on XML (but you actually never touch it, the XML is converted to objects by libraries).</p> <h1><span>Overview</span></h1> <p>We want to run an XML-RPC server exposing a class in PHP and an XML-RPC client in Python to communicate with the XML-RPC server.</p> <p>Traditionally we would need to have an HTTP server for the PHP XML-RPC server, because HTTP is used as the XML-RPC transport. But digging a bit into the specification, you'll discover, that none HTTP-specific parts of the protocol are used. It's just used as a line to transport the XML data.</p> <p>So you may wonder if it's possible to use XML-RPC with transport other than HTTP. In short, yes. But you may need to hack around the XML-RPC libraries (because they usually suppose you'll want to use HTTP).</p> <h1><span>PHP XML-RPC server</span></h1> <p>First, you need some class, that you want to expose with PHP XML-RPC:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">MyClass</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/** *</span><span class="hl-inlinedoc"> @param </span><span class="hl-comment">string $input *</span><span class="hl-inlinedoc"> @return </span><span class="hl-comment">string */</span><span class="hl-code"> </span><span class="hl-reserved">public</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">repeat</span><span class="hl-brackets">(</span><span class="hl-var">$input</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-var">$input</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-brackets">}</span> </pre></div> </div> <p>Notice I've set the parameter and return type in phpdoc.</p> <p>Now let's expose this class with <a href="http://framework.zend.com/manual/en/zend.xmlrpc.server.html#zend.xmlrpc.server.introduction">Zend Framework XML-RPC implementation</a>.</p> <p>You need to download Zend Framework first, let's say to /path/to/zf directory.</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">MyClass</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/** *</span><span class="hl-inlinedoc"> @param </span><span class="hl-comment">string $input *</span><span class="hl-inlinedoc"> @return </span><span class="hl-comment">string */</span><span class="hl-code"> </span><span class="hl-reserved">public</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">repeat</span><span class="hl-brackets">(</span><span class="hl-var">$input</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-var">$input</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-identifier">set_include_path</span><span class="hl-brackets">(</span><span class="hl-identifier">get_include_path</span><span class="hl-brackets">()</span><span class="hl-code"> . </span><span class="hl-reserved">PATH_SEPARATOR</span><span class="hl-code"> . </span><span class="hl-quotes">'</span><span class="hl-string">zf/library</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-reserved">require_once</span><span class="hl-code"> </span><span class="hl-quotes">&quot;</span><span class="hl-string">Zend/XmlRpc/Server.php</span><span class="hl-quotes">&quot;</span><span class="hl-code">; </span><span class="hl-var">$server</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Zend_XmlRpc_Server</span><span class="hl-brackets">()</span><span class="hl-code">; </span><span class="hl-var">$server</span><span class="hl-code">-&gt;</span><span class="hl-identifier">setClass</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">MyClass</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">myclass</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-reserved">echo</span><span class="hl-code"> </span><span class="hl-var">$server</span><span class="hl-code">-&gt;</span><span class="hl-identifier">handle</span><span class="hl-brackets">()</span><span class="hl-code">;</span> </pre></div> </div> <p>Set_include_path line adds the /path/to/zf/library directory to PHP path, so you can import the Zend_XmlRpc_Server class (located in /path/to/zf/library/Zend/XmlRpc/Server.php file).</p> <p>Then there is an instance of Zend_XmlRpc_Server created, then there is MyClass attached as the class for <strong>myclass</strong> XMLRPC namespace. This means the repeat method is to be called via the XML-RPC as <strong>myclass.repeat</strong>.</p> <p>If you place the file on your server and have it under some URL, for example:</p> <p><a href="http://your-server.com/myclass.php">http://your-server.com/myclass.php</a></p> <p>This URL is fully valid XML-RPC server endpoint for XML-RPC clients.</p> <h1><span>Python client</span></h1> <p>Having the XML-RPC server running we can connect to it from any XML-RPC enabled library in any programming language around.</p> <p>In Python, to call the remote procedure <strong>myclass.repeat</strong> on the XML-RPC endpoint <a href="http://your-server.com/myclass.php">http://your-server.com/myclass.php</a>, you would do the following:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">xmlrpclib</span><span class="hl-code"> </span><span class="hl-reserved">import</span><span class="hl-code"> </span><span class="hl-identifier">ServerProxy</span><span class="hl-code"> </span><span class="hl-identifier">server</span><span class="hl-code"> = </span><span class="hl-identifier">ServerProxy</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">http://your-server.com/myclass.php</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">print</span><span class="hl-code"> </span><span class="hl-identifier">server</span><span class="hl-code">.</span><span class="hl-identifier">myclass</span><span class="hl-code">.</span><span class="hl-identifier">repeat</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Hello RPC service</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span> </pre></div> </div> <p>Running this code:</p> <div class="code"> <pre> <code># python xmlrpc-test.py</code> </pre></div> <p>gives you:</p> <div class="code"> <pre> <code>Hello RPC service</code> </pre></div> <p>Under the hood:</p> <ul> <li>Python script makes a connection to <a href="http://your-server.com/myclass.php">http://your-server.com/myclass.php</a> <ul> <li>your webserver runs the myclass.php script <ul> <li>the $server-&gt;handle() line processes the data received <ul> <li>chooses a class and a method to run (this would be MyClass and repeat)</li> <li>passes the arguments (a string 'Hello RPC service') to the method</li> <li>gets the return value</li> </ul> </li> <li>passes it back to the client wrapped in XML-RPC protocol</li> </ul> </li> </ul> </li> <li>Python gets XML reply and converts it back to simple string ('Hello RPC service')</li> <li>and prints it on the console</li> </ul> <h1><span>Omitting the HTTP protocol</span></h1> <p>Probably you have both Python and PHP scripts to be run on the same machine, so the HTTP part is quite useless and an additional point of failure.</p> <p>As I already stated, the HTTP is only a transport and you can replace it (with some cost) with some other transport.</p> <p>I came into an idea to use stdout/stdin as the transport, so Python would execute a PHP script (command line interface) and pass the XML-RPC request to the script's stdin. PHP would then have to get the XML-RPC request from stdin instead of from HTTP request.</p> <p>This means two modifications in server and client code.</p> <p>First the server:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">MyClass</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/** *</span><span class="hl-inlinedoc"> @param </span><span class="hl-comment">string $input *</span><span class="hl-inlinedoc"> @return </span><span class="hl-comment">string */</span><span class="hl-code"> </span><span class="hl-reserved">public</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">repeat</span><span class="hl-brackets">(</span><span class="hl-var">$input</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-var">$input</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-identifier">set_include_path</span><span class="hl-brackets">(</span><span class="hl-identifier">get_include_path</span><span class="hl-brackets">()</span><span class="hl-code"> . </span><span class="hl-reserved">PATH_SEPARATOR</span><span class="hl-code"> . </span><span class="hl-quotes">'</span><span class="hl-string">zf/library</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-reserved">require_once</span><span class="hl-code"> </span><span class="hl-quotes">&quot;</span><span class="hl-string">Zend/XmlRpc/Server.php</span><span class="hl-quotes">&quot;</span><span class="hl-code">; </span><span class="hl-reserved">require_once</span><span class="hl-code"> </span><span class="hl-quotes">&quot;</span><span class="hl-string">Zend/XmlRpc/Request/Stdin.php</span><span class="hl-quotes">&quot;</span><span class="hl-code">; </span><span class="hl-var">$server</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Zend_XmlRpc_Server</span><span class="hl-brackets">()</span><span class="hl-code">; </span><span class="hl-var">$server</span><span class="hl-code">-&gt;</span><span class="hl-identifier">setClass</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">MyClass</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">myclass</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-reserved">echo</span><span class="hl-code"> </span><span class="hl-var">$server</span><span class="hl-code">-&gt;</span><span class="hl-identifier">handle</span><span class="hl-brackets">(</span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Zend_XmlRpc_Request_Stdin</span><span class="hl-brackets">())</span><span class="hl-code">;</span> </pre></div> </div> <p>The change is passing an instance of Zend_XmlRpc_Request_Stdin to $server-&gt;handle(). This is all needed. Guys from Zend Framework already predicted such a use.</p> <p>Then, the client part.</p> <p>Xmlrpclib allows passing a custom transport in case you want to implement some proxies or other thing. We'll make a transport, that instead of making a HTTP connection, runs a PHP script, passes the request to its stdin and gets the response from stdout:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">xmlrpclib</span><span class="hl-code"> </span><span class="hl-reserved">import</span><span class="hl-code"> </span><span class="hl-identifier">Transport</span><span class="hl-code">, </span><span class="hl-identifier">Server</span><span class="hl-code"> </span><span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">subprocess</span><span class="hl-code"> </span><span class="hl-reserved">import</span><span class="hl-code"> </span><span class="hl-identifier">Popen</span><span class="hl-code">, </span><span class="hl-identifier">PIPE</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">LocalFileTransport</span><span class="hl-brackets">(</span><span class="hl-identifier">Transport</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">Connection</span><span class="hl-code">: </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">setCmd</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">cmd</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmd</span><span class="hl-code"> = </span><span class="hl-identifier">Popen</span><span class="hl-brackets">([</span><span class="hl-quotes">'</span><span class="hl-string">php</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">cmd</span><span class="hl-brackets">]</span><span class="hl-code">, </span><span class="hl-identifier">stdin</span><span class="hl-code">=</span><span class="hl-identifier">PIPE</span><span class="hl-code">, </span><span class="hl-identifier">stdout</span><span class="hl-code">=</span><span class="hl-identifier">PIPE</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">send</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">content</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmd</span><span class="hl-code">.</span><span class="hl-identifier">stdin</span><span class="hl-code">.</span><span class="hl-identifier">write</span><span class="hl-brackets">(</span><span class="hl-identifier">content</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmd</span><span class="hl-code">.</span><span class="hl-identifier">stdin</span><span class="hl-code">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">getreply</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-number">200</span><span class="hl-code">, </span><span class="hl-quotes">''</span><span class="hl-code">, </span><span class="hl-brackets">[]</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">getfile</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmd</span><span class="hl-code">.</span><span class="hl-identifier">stdout</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">make_connection</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">host</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">Connection</span><span class="hl-brackets">()</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">send_request</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">connection</span><span class="hl-code">, </span><span class="hl-identifier">handler</span><span class="hl-code">, </span><span class="hl-identifier">request_body</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-identifier">connection</span><span class="hl-code">.</span><span class="hl-identifier">setCmd</span><span class="hl-brackets">(</span><span class="hl-identifier">handler</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">send_content</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">connection</span><span class="hl-code">, </span><span class="hl-identifier">request_body</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-identifier">connection</span><span class="hl-code">.</span><span class="hl-identifier">send</span><span class="hl-brackets">(</span><span class="hl-identifier">request_body</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">send_host</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">connection</span><span class="hl-code">, </span><span class="hl-identifier">host</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">pass</span><span class="hl-code"> </span><span class="hl-reserved">def</span><span class="hl-code"> </span><span class="hl-identifier">send_user_agent</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">connection</span><span class="hl-brackets">)</span><span class="hl-code">: </span><span class="hl-reserved">pass</span><span class="hl-code"> </span><span class="hl-identifier">server</span><span class="hl-code"> = </span><span class="hl-identifier">Server</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">http://host.com/path/to/the/php/script/myclass.php</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">transport</span><span class="hl-code"> = </span><span class="hl-identifier">LocalFileTransport</span><span class="hl-brackets">())</span><span class="hl-code"> </span><span class="hl-reserved">print</span><span class="hl-code"> </span><span class="hl-identifier">server</span><span class="hl-code">.</span><span class="hl-identifier">myclass</span><span class="hl-code">.</span><span class="hl-identifier">repeat</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Hello XML-RPC with no HTTP service</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span> </pre></div> </div> <p>Notes:</p> <ul> <li>host.com in the URL is completely ignored, use whatever value you want</li> <li>/path/to/the/php/script/myclass.php in URL is passed as the PHP script to run</li> </ul> <h1><span>What to do next?</span></h1> <p>Having this simple skeleton, you can now extend the MyClass, actually give it more proper name first! You can also attach more classes to the XML-RPC server using different namespaces:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-code">$server-&gt;setClass('SomeClass', 'some); $server-&gt;setClass('MyClass', 'my'); $server-&gt;setClass('YourClass', 'your');</span> </pre></div> </div> <p>Only public methods are exposed to the XML-RPC clients, so you can hide some logic inside of private or protected methods and only expose what you need from given classes.</p> <p>This solution is a quick way to actually use some of your well-working PHP code in your fancy-new and elegant Python application. This can help if you want to make a filesystem with Python-FUSE, but want to data be taken from PHP application.</p> <h1><span>Did it help you?</span></h1> <p>I hope this helps someone. Feel free to comment.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:wikidot-search-ready-to-test</guid>
				<title>Wikidot Search Ready To Test</title>
				<link>http://piotr.gabryjeluk.pl/dev:wikidot-search-ready-to-test</link>
				<description>

&lt;p&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/dev:new-search-for-wikidot-s-gonna-rock&quot;&gt;Lucene-based search&lt;/a&gt; - a brand new feature has been being introduced to Wikidot code for quite a long time.&lt;/p&gt;
&lt;p&gt;After that time of developing and dealing with performance problems (searching the whole Wikidot in 3 seconds is too long!) it&#039;s time for test this thing!&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 18 Dec 2008 23:22:47 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p><a href="http://piotr.gabryjeluk.pl/dev:new-search-for-wikidot-s-gonna-rock">Lucene-based search</a> - a brand new feature has been being introduced to Wikidot code for quite a long time.</p> <p>After that time of developing and dealing with performance problems (searching the whole Wikidot in 3 seconds is too long!) it's time for test this thing!</p> <div class="content-separator" style="display: none:"></div> <table style="margin:0; padding:0"> <tr> <td style="margin:0; padding:0"> <div id="toc"> <div id="toc-action-bar"><a href="javascript:;" >Fold</a><a style="display: none" href="javascript:;" >Unfold</a></div> <div class="title">Table of Contents</div> <div id="toc-list"> <div style="margin-left: 1em;"><a href="#toc0">Introduction</a></div> <div style="margin-left: 2em;"><a href="#toc1">Fresh install</a></div> <div style="margin-left: 2em;"><a href="#toc2">Existing install</a></div> <div style="margin-left: 1em;"><a href="#toc3">Features</a></div> <div style="margin-left: 1em;"><a href="#toc4">Test it!</a></div> <div style="margin-left: 1em;"><a href="#toc5">Extras</a></div> <div style="margin-left: 2em;"><a href="#toc6">Highlighting</a></div> <div style="margin-left: 2em;"><a href="#toc7">Need more performance or memory limit exhausted</a></div> <div style="margin-left: 1em;"><a href="#toc8">Summary</a></div> </div> </div> </td> </tr> </table> <h1><span>Introduction</span></h1> <p>The whole thing is about Search All Sites module for Wikidot Open Source. This entry is mainly for those of you that run their own Wikidot services. More info on getting Wikidot software run can be found on <a href="http://my-wd-local.wikidot.com/guide:ubuntu-8-04-with-lighttpd-install">Ed's site</a>.</p> <h2><span>Fresh install</span></h2> <p>After installing Wikidot Open Source from current version, you can instantly test the new Search All Sites module. Just navigate to <strong>/search:all</strong> page of your main wiki. Example: if your wiki farm runs on the domain <strong>mydomain.com</strong> and your main wiki is <strong>www.mydomain.com</strong>, navigate to <a href="http://www.mydomain.com/search:all">http://www.mydomain.com/search:all</a>.</p> <h2><span>Existing install</span></h2> <p>Updating to the new search engine from already installed version is quite tricky, because you need to pre-populate the search index (which is the actual file that is searched by the index, when looking for term user entered).</p> <p>You can try the following commands:</p> <ul> <li>obtain root priviledges</li> </ul> <div class="code"> <pre> <code>sudo su</code> </pre></div> <ul> <li>navigate to your Wikidot directory (it is /var/www/wikidot by default), update the code and run the lucene_bootstrap.php script as your lighttpd user</li> </ul> <div class="code"> <pre> <code>cd /var/www/wikidot svn update cd tests sudo -u www-data php lucene_bootstrap.php</code> </pre></div> <p>This command adds every page to the index (normally located at /var/www/wikidot/tmp/lucene_index). Once indexed a page can be searched (if the site containing the page is public or you're a member of the site). The command prints a dot for each 10 indexed items (item is every page and forum/comments thread).</p> <p>If this runs smoothly (i.e. no error, Segmentation fault at the end is OK, but <strong>memory exhausted is not OK</strong>) you have all your sites indexed and ready to search through.</p> <p><strong>When it fails:</strong> you can increase the max_memory setting in the corresponding php.ini file and re-run the command. There is no bad thing in running this command more than once as indexing a page always deletes the page from index before adding it again.</p> <p>Just go to <strong>/search:all</strong> location at your main wiki and search for some content.</p> <p>Also you need to update your crontab file. Add:</p> <div class="code"> <pre> <code>* * * * * www-data /var/www/wikidot/bin/job.sh UpdateLuceneIndexJob</code> </pre></div> <br /> to your /etc/crontab (assuming you have wikidot in /var/www/wikidot/). This will add an every-minute job indexing pages and threads queued to index when saving or changing public/private site state. <h1><span>Features</span></h1> <ul> <li>First of all the new search applies only to the <strong>Search All Sites</strong> i.e. <strong>Search This Site</strong> works in the old way.</li> <li>Search uses titles and tags intelligently <ul> <li>pages with the exact search phrase in the title are placed higher in the result list</li> <li>pages with tags matching search phrase are quite high in the result list</li> <li>pages with title matching search phrase are quite high in the result list</li> <li>pages with content matching search phrase are somewhere low in result list</li> <li>pages with parts of search phrase matching titles and tags can be higher in the result list than the pages having content matching even the exact phrase</li> <li>this all means: <strong>tags and titles are more important than content for the search engine</strong></li> </ul> </li> <li>You can narrow your search to only selected wikis <ul> <li>append <strong>site:site1,site2,site3</strong> (no spaces between them) to your search query. Example: search for &quot;<strong>gabrys site:www,community</strong>&quot; searches for <strong>gabrys</strong> in titles, tags and contents of pages and threads inside of sites <strong>www</strong>.yourdomain.com and <strong>community</strong>.yourdomain.com (supposing your Wikidot installation runs on yourdomain.com)</li> </ul> </li> <li>The search includes public sites plus sites you are a member of. Also the results from your sites are generally more relevant to the search engine (i.e. they appear higher than the results from other sites)</li> <li>The search results for given phrase for given user are cached (if memcached is used) for a few minutes. This makes the search even more smooth (no need to search the index again when user only switches the result page from 2 to 3 for example)</li> </ul> <h1><span>Test it!</span></h1> <p>If you don't run and don't want to run your own Wikidot installation, you can try the new features on the following site:</p> <p style="text-align: center;"><a href="http://www.wikicomplete.info/search:all">http://www.wikicomplete.info/search:all</a></p> <h1><span>Extras</span></h1> <h2><span>Highlighting</span></h2> <p>Like Google's way to highlight the searched words in Google-cached versions of result pages? Now you can add this feature to your Wikidot installation as well.</p> <p>Open <strong>conf/wikidot.ini</strong> file and append those lines:</p> <div class="code"> <pre> <code>[search] ; enables highlighting of search phrase in the resulting documents highlight = true</code> </pre></div> <p>This will highlight the words user searched for using:</p> <ul> <li>Google Search</li> <li>Yahoo Search</li> <li>Your Wikidot installation search:all page</li> </ul> <h2><span>Need more performance or memory limit exhausted</span></h2> <p>We experienced some low performance when searching through 2 millions of pages and threads of Wikidot.com. The search results were generated in about 3 seconds. This was not enough for us, so we manage to speed things up using the native <a href="http://lucene.apache.com">Java Lucene implementation</a> for searching the index. This works because we use <a href="http://framework.zend.com/manual/en/zend.search.lucene.html">PHP Lucene implementation</a> that is compatible with the Java's one. This means we can index page with PHP and search with Java. And we do it! If you want do this too (experiencing low search performance of getting memory exhausted error messages), just add the following lines to your <strong>conf/wikidot.ini</strong> file:</p> <div class="code"> <pre> <code>[search] ; enables the use of Java for searching use_java = true</code> </pre></div> <p>Notes</p> <ul> <li>if you already have [search] section in the <strong>conf/wikidot.ini</strong> file, just add the <tt>use_java = true</tt> line in the search section</li> <li>enabling Java for searching requires you to install java executable for your system. You should know how to do this (try sudo aptitude install openjdk-6-jre).</li> <li>you don't need any Java libraries as we already bundled everything needed in the .jar file. The Java source and Ant build script is located normally at the <tt>/var/www/wikidot/java</tt> directory (assuming you installed the wikidot in <tt>/var/www/wikidot</tt>.</li> </ul> <h1><span>Summary</span></h1> <p>Once we assure the search is stable and gives relevant results, we'll introduce it to the Wikidot.com service. I calculated that indexing all the sites would take about 3 days! But searching is done in less than 1 second (using the Java program).</p> <p>I'm looking for your comment on the features. Especially if you've tried them yourself!</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:new-search-for-wikidot</guid>
				<title>New Search For Wikidot</title>
				<link>http://piotr.gabryjeluk.pl/dev:new-search-for-wikidot</link>
				<description>

&lt;p&gt;As some of you already noticed, we now use Google Custom Search for searching the whole Wikidot. The reason for this was quite obvious.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 03 Dec 2008 20:58:09 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>As some of you already noticed, we now use Google Custom Search for searching the whole Wikidot. The reason for this was quite obvious.</p> <p>We now host 2 million pages and the full text search engine we had used was not fast enough to satisfy a regular user. The average search time (in all wikis) was about 30 seconds.</p> <p>Google searches the whole Wikidot in less than 1 second. The downsides of using Google engine are:</p> <ul> <li>using external service &#8212; prestige and dependence</li> <li>displaying ads on search results &#8212; for those who don't use AdBlock</li> <li>pages get indexed after some significant time</li> <li>only public wikis can be indexed</li> </ul> <p>One important thing is Google indexes every content from a site. This includes Wikidot.com footer, menus, wiki header, the real content and tags. All of these is treated in an unknown way, so we have no <strong>big/real</strong> impact on how Google treats different portions of pages.</p> <p>This leads to a conclusion, that we need a search engine.</p> <p>We would like:</p> <ul> <li>to treat tags as more important than the regular content</li> <li>not to search from Wikidot.com static elements (like the footer on every page)</li> <li>allow searching all wikis available for given user <ul> <li>all public wikis</li> <li>all private wikis that the user is a member of</li> </ul> </li> </ul> <p>Coming to technical details, one could say, we just need a generic <strong>full text search engine</strong>. We can use one available in our storage system or one of dedicated search-only engines.</p> <h1><span>Tsearch</span></h1> <p><strong>Tsearch</strong> &#8212; the full text search engine for PostgreSQL (storage used for Wikidot data) is currently used when searching a wiki. This is quite nicely integrated and plays well. But when there are over 20,000 wikis to search (I mean only non-spam public ones), the efficiency is not enough.</p> <h1><span>Lucene</span></h1> <p><strong>Lucene</strong> &#8212; one of the most popular search engines for Java is one of the possible choices. The mechanism it works is the following:</p> <ul> <li>application pulls some <em>documents</em> to the search <em>index</em> <ul> <li><em>document</em> is a webpage in our situation</li> <li><em>index</em> is a datastore to be used when searching</li> </ul> </li> <li>user queries the <em>index</em> with a query <ul> <li>a bunch of <em>documents</em> is returned in the order of relevance</li> <li>the <em>documents</em> returned are more or less the same as the documents pulled to the index before</li> </ul> </li> </ul> <p>This mechanism requires populating index by application</p> <ul> <li>updating the index every now and then</li> <li>updating document on some change &#8212; like page edit</li> </ul> <p>and requires us to define some functions that deal with search results</p> <ul> <li>the original webpage is usually not stored in the index, but only tokenized, to allow finding it when searching for any word in the document <ul> <li>this makes the index smaller and faster</li> <li>this makes we need to store an additional ID of a webpage, to be able to retrieve the full result from the database based on the stored ID</li> </ul> </li> </ul> <h1><span>Nutch</span></h1> <p><strong>Nutch</strong> would be a different &#8212; more <em>Googlish</em> &#8212; approach to the search issue. Nutch indexes mainly HTML files (given URLs) and crawls through the the links. This has both advantages and disadvantages:</p> <p>The main advantage of using Nutch is that as a search result we get a formatted HTML document</p> <ul> <li>with links to items found</li> <li>with context of the search phrase quoted</li> <li>the search phrase words outlined in some way</li> </ul> <p>This is very similar to what we get searching for some phrase with Google.</p> <p>What I don't like about Nutch is quite big overhead of populating the index. A page must be compiled by the server and HTML must be produced. Then the same HTML must be parsed by the search engine to get important data. There is a lot of information generated by the server and then forgot by the search engine.</p> <p>Nutch (similar to Lucene) is a Java project and requires some Java environment. This may and may not be a problem, but is a point we must concern when looking for optimal solution.</p> <p>There is <strong>OpenSearch</strong> project which aims to make the Nutch results more interchangeable (exporting them as RSS feeds). Using it a PHP application can safely ask for results a HTTP service and get RSS feed to parse and present to user.</p> <h1><span>Zend_Search_Lucene</span></h1> <p>There is also a quite nice thing around: <strong>Zend_Search_Lucene</strong>. It is a search engine written entirely in PHP being a part of Zend Framework for PHP. The internal format of the search index file is compatible with Lucene and this is where the name of the package comes from. Also the query language is the same (or very similar).</p> <p>It seems, the PHP implementation should be really slow, when searching really big sets of data, but after some testing, we get the search results for almost any query in about 1 second, searching almost the whole Wikidot.</p> <p>I think this is a really nice solution, because it can integrate well with the existing PHP code of Wikidot. Also the searching can be easily parallelized for many machines. For example, you can have 4 search machines, each getting 1/4 of search queries to carry out. This way we don't reduce the search time, but avoid searching many things in one index at once.</p> <p>There are some options to consider when dividing the search queries to different machines. We can select the machine to perform the search by random, by turn or by search hash. Search hash would make a MD5 sum (or other hash) of a query, compute the modulo rest from division by number of machines from the hash (treated as an integer) and assign the search to the machine having number of computed modulo. This means the same query will always be performed on the same machine (it can be then better cached or optimized).</p> <p>The Zend implementation of Lucene is also really trivial to understand and use, so it seems a good start for me. Testing it on the whole public part of Wikidot I got a index of about 500&#160;MB. Adding a single page to the index of this size takes about 2 seconds. Searching &#8212; about 1 second.</p> <h1><span>Sphinx</span></h1> <p>When I have asked my friend about full text search engines he recommends, he pointed out <strong>Sphinx</strong> &#8212; standalone application for this purpose. It is not very popular software as it haven't find it way to the Ubuntu repository for example, but it seems very interesting.</p> <p>Sphinx can be fed with XML streams of data from any application, can fetch data from PostgreSQL or MySQL databases or be communicated with via its API and libraries to many languages.</p> <p>It seems it's somehow similar to Lucene, but implemented using traditional languages, not Java.</p> <h1><span>The choice</span></h1> <p>There are probably some other solutions that are worth trying, but I think the most appropriate for now is using the Zend's one as it's the easiest to adapt. We can optionally use some caching mechanisms and queries distribution. Also we need more testing of situations that may appear (like a need to perform 100 queries simultaneously).</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:doctrine-php</guid>
				<title>Doctrine PHP</title>
				<link>http://piotr.gabryjeluk.pl/dev:doctrine-php</link>
				<description>

&lt;p&gt;A few days ago, I found &lt;a href=&quot;http://www.doctrine-project.org/&quot;&gt;Doctrine Project&lt;/a&gt; which is an object-relational mapping (ORM) solution for PHP. It seems really powerful and actually very similar to Wikidot DB Layer (especially one in Wikidot 2).&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 30 Oct 2008 19:48:55 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>A few days ago, I found <a href="http://www.doctrine-project.org/">Doctrine Project</a> which is an object-relational mapping (ORM) solution for PHP. It seems really powerful and actually very similar to Wikidot DB Layer (especially one in Wikidot 2).</p> <p>Doctrine is a really cool project and has features of:</p> <ul> <li>Wikidot DB</li> <li>Zend Framework DB</li> <li>Hibernate (ORM for Java)</li> <li>Ruby on Rails DB</li> </ul> <p>Let's start from the beginning of the list.</p> <p>Doctrine is most similar to Wikidot DB, because both:</p> <ul> <li>are ORM implementations for PHP</li> <li>use abstract (non-PHP, non-SQL) data definition language <ul> <li>for Wikidot it's XML-based format</li> <li>for Doctrine it's YAML-based one</li> </ul> </li> </ul> <p>It's similar to Zend Framework DB, because of:</p> <ul> <li>using magic PHP methods for accessing objects properties</li> </ul> <p>Hibernate and Doctrine shares:</p> <ul> <li>completeness of the DB layer</li> <li>higher abstraction than other DB layers</li> </ul> <p>Ruby On Rails concepts in Doctrine:</p> <ul> <li>using YAML as a model definition language</li> <li>independence of database engine</li> </ul> <p>Example of model definition:</p> <div class="code"> <pre> <code>User: columns: id: type: integer primary: true autoincrement: true login: type: string(64) unique: true notnull: true realname: type: string password: type: string(64) notnull: true im: type: string(64) token_active: type: string token_created: type: timestamp Bet: columns: id: type: integer primary: true autoincrement: true brand: type: string(100) notnull: true qty: type: integer default: 1 notnull: true unit: type: string(100) notnull: true BetUser: columns: bet_id: type: integer primary: true user_id: type: integer primary: true wins_if: type: string notnull: true detect_relations: true</code> </pre></div> <p>Doctrine comes with a CLI tool, that offers the following things:</p> <div class="code"> <pre> <code>Doctrine Command Line Interface ./doctrine.php create-tables ./doctrine.php rebuild-db ./doctrine.php generate-models-db ./doctrine.php generate-models-yaml ./doctrine.php generate-yaml-db ./doctrine.php load-data ./doctrine.php build-all-load ./doctrine.php generate-migrations-models ./doctrine.php build-all ./doctrine.php create-db ./doctrine.php migrate ./doctrine.php generate-yaml-models ./doctrine.php dump-data ./doctrine.php dql ./doctrine.php generate-migrations-db ./doctrine.php compile ./doctrine.php generate-sql ./doctrine.php drop-db ./doctrine.php generate-migration ./doctrine.php build-all-reload</code> </pre></div> <p>The tool can be used to generate PHP files from YAML files, generate SQL files (for given DB engine), drop and create the database and more.</p> <p>The dql seems to be an interesting option. Doctrine supplies its own backend-independent SQL-like language for querying and updating the DB. These operations can be done with the dql option. Although I haven't tested it yet, it seems perfect for some cronjobs or other automatic tasks that don't need to be coded in PHP.</p> <p><strong>&lt;OFF-TOPIC&gt;</strong><br /> Now, I'm converting my nuclear project &#8212; opiwo.com (bet a beer in Polish) to Doctrine ORM (from Zend Framework's one) to see how it works in reality. The project uses also other nice technologies like JSON-RPC.</p> <p>I'm willing to minimize the work needed to launch it soon, by using bleeding edge technologies and web service programming concepts. The whole user interface part is programmed in JavaScript, jQuery (with many plugins) and static HTML files. Only pure data is fetched from server (with JSON-RPC). This gives more power to the server and user more responsive interface to the user. On the other side, the website <strong>may</strong> be more CPU-intensive (I hope not too much).<br /> <strong>&lt;/OFF-TOPIC&gt;</strong></p> <p>Please forgive me I'm now quite excited about the Doctrine. It's just how I react to some really cool (well-designed) things. I hope it's <strong>really that cool</strong> :).</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:php-routing-like-in-django</guid>
				<title>Django-like routing in PHP</title>
				<link>http://piotr.gabryjeluk.pl/dev:php-routing-like-in-django</link>
				<description>

&lt;p&gt;As I&#039;ve recently work with Django, the way it does the URL-based routing seemed really cool for me. I missed that in PHP, so I decided to code something like this.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Sat, 05 Jul 2008 16:06:32 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>As I've recently work with Django, the way it does the URL-based routing seemed really cool for me. I missed that in PHP, so I decided to code something like this.</p> <p>Here is a class that <strong>uses</strong> (extends) my Controller class that does the routing:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-inlinetags">&lt;?php</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code"> </span><span class="hl-identifier">Controller_Ajax_Auth</span><span class="hl-code"> </span><span class="hl-reserved">extends</span><span class="hl-code"> </span><span class="hl-identifier">Controller_Ajax</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-reserved">protected</span><span class="hl-code"> </span><span class="hl-var">$routes</span><span class="hl-code"> = </span><span class="hl-reserved">Array</span><span class="hl-brackets">(</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-string">:^info$:</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">info</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">:^challenge$:</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">challenge</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">:^login$:</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">login</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">:^logout$:</span><span class="hl-quotes">'</span><span class="hl-code"> =&gt; </span><span class="hl-quotes">'</span><span class="hl-string">logout</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-reserved">protected</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">info</span><span class="hl-brackets">(</span><span class="hl-var">$url</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-var">$r</span><span class="hl-code"> = </span><span class="hl-reserved">Array</span><span class="hl-brackets">()</span><span class="hl-code">; </span><span class="hl-comment">/* something */</span><span class="hl-code"> </span><span class="hl-var">$this</span><span class="hl-code">-&gt;</span><span class="hl-identifier">ajaxResponse</span><span class="hl-brackets">(</span><span class="hl-var">$r</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-reserved">protected</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">challenge</span><span class="hl-brackets">(</span><span class="hl-var">$url</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/* $q = something */</span><span class="hl-code"> </span><span class="hl-var">$this</span><span class="hl-code">-&gt;</span><span class="hl-identifier">ajaxResponse</span><span class="hl-brackets">(</span><span class="hl-var">$q</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-reserved">protected</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">login</span><span class="hl-brackets">(</span><span class="hl-var">$url</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/* set $auth to true if logged */</span><span class="hl-code"> </span><span class="hl-var">$this</span><span class="hl-code">-&gt;</span><span class="hl-identifier">ajaxResponse</span><span class="hl-brackets">(</span><span class="hl-var">$auth</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-reserved">protected</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">logout</span><span class="hl-brackets">(</span><span class="hl-var">$url</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"> </span><span class="hl-comment">/* logout */</span><span class="hl-code"> </span><span class="hl-var">$this</span><span class="hl-code">-&gt;</span><span class="hl-identifier">ajaxResponse</span><span class="hl-brackets">(</span><span class="hl-reserved">null</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-brackets">}</span> </pre></div> </div> <p>This mainly routes URLs info, challenge, login and logout to corresponding methods in the same object.</p> <p>But you can route out of the object to other Controller subclass instance:</p> <div class="code"> <div class="hl-main"> <pre> <span class="hl-code"> protected $routes = Array( ':^auth/(.*)$:' =&gt; 'Controller_Ajax_Auth', );</span> </pre></div> </div> <p>This gets URL and passes what's after auth/ to the new object of class Controller_Ajax_Auth (see the code above). Generally the first ()s in the left side of each line define what's passed to the method/object on the right side.</p> <p>The controller has abstract errorHandler and defaultAction methods that need to be overridden. The first is called when a exception is thrown in a performed action. The latter is called, when routing comes to some object and then no routing line matches.</p> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://piotr.gabryjeluk.pl/dev:mirror-server</guid>
				<title>Mirror Server</title>
				<link>http://piotr.gabryjeluk.pl/dev:mirror-server</link>
				<description>

&lt;p&gt;Today I&#039;ve (almost) managed to create a mirror server for wikidot.com service.&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=2462&amp;amp;size=small&amp;amp;timestamp=1328999336&quot; alt=&quot;Gabrys&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=2462)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://piotr.gabryjeluk.pl/profile2:2462&quot; target=&quot;_blank&quot;&gt;Gabrys&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 24 Jun 2008 12:55:35 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>Today I've (almost) managed to create a mirror server for wikidot.com service.</p> <p>Features:</p> <ul> <li><strong>CentOS</strong> distribution</li> <li>almost live Wikidot read only mirror</li> <li>database is replicated from the original service in real time to this server</li> <li>user uploaded files are replicated in real time to this server using <a href="http://piotr.gabryjeluk.pl/fs-mirror">FS mirror</a></li> <li>avatars <strong>are to be</strong> mirrored with rsync every now and then</li> <li>uses Portable IP address: 67.228.37.27</li> <li><strong>lighttpd</strong> serves ALL content with FastCGI PHP</li> <li>database is <strong>read-only</strong> (as being replication slave)</li> <li>CVS configured to use SSH keys (no password asking)</li> <li>Wikidot PHP source mainly from the current production server</li> <li>Improvements (from CVS): uploaded files served like in OpenSource version</li> </ul> <p>Problems:</p> <ul> <li><a href="http://piotr.gabryjeluk.pl/fs-mirror">FS mirror</a> is not 100% exact, it may not synchronize some (little fraction of) files every now and then, so we must rsync them additionally, to make sure nothing's lost</li> <li>if you were logged in to Wikidot before, it'll complain about not being able to write to ozone_session (because it's read only)</li> <li><span style="text-decoration: line-through;">Flickr Gallery not working and causing the whole page to display just nothing</span></li> <li><span style="text-decoration: line-through;">magic file recognition not working (it may be a problem in PHP configuration or an extension):</span></li> </ul> <div class="code"> <pre> <code>PHP Warning: finfo_open(): Failed to load magic database at '/usr/share/misc/magic'. in /var/www/www.wikidot.com/wikidot/php/utils/- on line 3 PHP Warning: finfo_file(): supplied argument is not a valid file_info resource in /var/www/www.wikidot.com/wikidot/php/utils/- on line 4 PHP Warning: finfo_close(): supplied argument is not a valid file_info resource in /var/www/www.wikidot.com/wikidot/php/utils/- on line 5</code> </pre></div> <p>UPDATE: Flickr problem solution:</p> <ol> <li>yum install php-pear-HTTP-Request</li> <li>chgrp lighttpd /var/lib/php/session</li> </ol> <p>Remember:</p> <ul> <li>when switching to mirror, we must restart memcached (or force to invalidate every item in it)</li> </ul> <p>by <span class="printuser avatarhover"><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank"><img class="small" src="http://www.wikidot.com/avatar.php?userid=2462&amp;size=small&amp;timestamp=1328999336" alt="Gabrys" style="background-image:url(http://www.wikidot.com/userkarma.php?u=2462)" /></a><a href="http://piotr.gabryjeluk.pl/profile2:2462" target="_blank">Gabrys</a></span></p> 
				 	]]>
				</content:encoded>							</item>
				</channel>
</rss>
