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

<channel>
	<title>Full of BS &#187; PHP</title>
	<atom:link href="http://fullof.bs/category/programming/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://fullof.bs</link>
	<description>He just never stops talking</description>
	<lastBuildDate>Thu, 15 Dec 2011 20:00:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Gearing Up for Public SVN</title>
		<link>http://fullof.bs/gearing-up-for-public-svn/</link>
		<comments>http://fullof.bs/gearing-up-for-public-svn/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 16:01:46 +0000</pubDate>
		<dc:creator>John Haugeland</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[ECMA / Javascript]]></category>
		<category><![CDATA[ECMAScript]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Game Algorithms]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tools and Libraries]]></category>
		<category><![CDATA[Web and Web Standards]]></category>
		<category><![CDATA[a*]]></category>
		<category><![CDATA[astar]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[embeddable]]></category>
		<category><![CDATA[htstub]]></category>
		<category><![CDATA[Public svn]]></category>
		<category><![CDATA[regression test]]></category>
		<category><![CDATA[scastar a star]]></category>
		<category><![CDATA[scutil]]></category>
		<category><![CDATA[stochastic test]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[unit test]]></category>
		<category><![CDATA[webserver]]></category>

		<guid isPermaLink="false">http://fullof.bs/?p=271</guid>
		<description><![CDATA[I&#8217;m going to be releasing a few new libraries in the next several days, both by archive and public subversion.  I&#8217;ve already bought the domains and built a forum for them.  I even wasted a couple hours subversion automating everything down to the line of having little library websites made automatically, with custom per-library color [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to be releasing a few new libraries in the next several days, both by archive and public subversion.  I&#8217;ve already bought the domains and built a forum for them.  I even wasted a couple hours subversion automating everything down to the line of having little library websites made automatically, with custom per-library color palettes.</p>
<p>I was a little bored.</p>
<p>So we&#8217;re going to have three libraries progressing in the immediate future, with quite a few more over time:</p>
<ol>
<li><a title="HtStub - an embeddable Erlang webserver" href="http://htstub.com/" target="_blank">HtStub</a> &#8211; An embeddable, zero-config, zero-behavior secure Erlang webserver</li>
<li><a title="StoneCypher's A* library, with tutorial" href="http://scastar.com/" target="_blank">SC A-Star</a> &#8211; An efficient, modular ECMAscript (flash/actionscript, javascript, jscript etc) A* implementation with support for custom grid geometries (<em>includes algorithm tutorial</em>)</li>
<li><a title="TestErl - an erlang library for unit, regression and stochastic testing" href="http://testerl.com/" target="_blank">TestErl</a> &#8211; unit, regression and stochastic testing for Erlang</li>
<li><a title="ScUtil - StoneCypher's erlang utility library" href="http://scutil.com/" target="_blank">ScUtil</a> &#8211; a fairly large list of gap filling functionality for Erlang</li>
</ol>
<p>In the near future, I will add C++ and PHP libraries, as well as many some libraries for more obscure languages like FormulaONE, Mozart-Oz, Factor and maybe (sadly) Delphi.  I have more than 30 libraries ready for release.</p>
<p>All those repos are pretty empty at the moment.  That will change in coming days, and I&#8217;m sure I&#8217;ll post lots of boring little snippets here about whatever minor new thing my crap does.</p>
<p>Yay!</p>
]]></content:encoded>
			<wfw:commentRss>http://fullof.bs/gearing-up-for-public-svn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stone PHP SafeCrypt: Convenient, Secure and Typesafe Encryption (Tutorial, Library and Test Code)</title>
		<link>http://fullof.bs/stone-php-safecrypt-convenient-secure-and-typesafe-encryption-tutorial-library-and-test-code/</link>
		<comments>http://fullof.bs/stone-php-safecrypt-convenient-secure-and-typesafe-encryption-tutorial-library-and-test-code/#comments</comments>
		<pubDate>Sun, 10 Sep 2006 02:47:56 +0000</pubDate>
		<dc:creator>John Haugeland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tools and Libraries]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.sc.tri-bit.com/archives/101</guid>
		<description><![CDATA[When wandering around Das Intarweb one sees a lot of sad, sad code. In fact, people who should know better get busted on weak crypto all the time. Indeed, even the PHP manual examples have unacceptable security flaws. When one is writing encryption code for one&#8217;s own site, that turns into a problem. Here&#8217;s a [...]]]></description>
			<content:encoded><![CDATA[<p>When wandering around Das Intarweb one sees a lot of sad, sad code.  In fact, <a title="Yes, that Don of Dons" href="http://dsc.discovery.com/news/briefs/20060417/mafiaboss_tec.html?source=rss">people who should know better</a> get busted on weak crypto all the time.   Indeed, even the PHP manual examples have unacceptable security flaws. When one is writing encryption code for one&#8217;s own site, that turns into a problem.  Here&#8217;s a library to wrap and a little primer on using the standard encryption facilities in PHP safely and correctly.</p>
<p><span id="more-160"></span></p>
<p>See, there are a lot of subtle attacks one can bring to bear on even sound cryptological systems, if one doesn&#8217;t know what one is doing.  PHP does a pretty neat job of wrapping up these issues behind a <a title="Mcrypt encryption library" href="http://php.net/mcrypt">semi-generic library interface</a>, but it doesn&#8217;t do such a great job in the manual of detailing safe usage.  In particular, some of the user notes give conflicting, and frequently outright bad, advice; furthermore, the displayed methods for using the interface aren&#8217;t themselves particularly generic, and skip some particularly useful things they could do.  It also doesn&#8217;t help that there&#8217;s a distinct trend of more-than-one-way-itis in libmcrypt, including a lot of support for deprecated functionality.</p>
<p>So, what to do about it, but write a new tute?  Actually, this one&#8217;s pretty low-impact; might as well just release it almost as straight source. Still, it&#8217;s helpful to explain.</p>
<h1>The Quick Version</h1>
<p>It&#8217;s surprisingly simple.</p>
<p>If you just want to throw the library in and start working, follow <a href="http://sc.tri-bit.com/outgoing/StonePhpSafeCrypt.zip">this download link</a>, then throw the file in with the rest of your PHP project.  Change the define <strong>DEFAULT_MD5_SALT</strong> on line 36 of StonePhpSafeCrypt_config.php (the library will force you to do this) and fill it with some random string.  Really doesn&#8217;t matter, and you&#8217;ll never need to remember it; it&#8217;s just a &#8220;salt,&#8221; which is used to prevent dictionary attacks.  Don&#8217;t use a phrase someone can guess, and consider just mashing your hands all over the keyboard for a second instead of trying to make up something smart.</p>
<p>Next, <strong>require_once()</strong> the library, then use <strong>PackCrypt(<em>$data, $key</em> </strong><span style="font-size: 80%;color: #557799"><strong><em>[, $options]</em></strong></span><strong> )</strong> and <strong>UnpackCrypt(<em>$data, $ke</em></strong><strong><em>y </em></strong><span style="font-size: 80%;color: #557799"><strong><em>[, $options] </em></strong></span><strong>)</strong> on any serializable PHP datatype.  $key does not need to be secure, except against social engineering attacks like guessing according to the user&#8217;s behavior; it is hardened by the library, and salted by you.</p>
<p>As options, you may pass in an array containing up to four things as key/value pairs:</p>
<ul>
<li>&#8216;<tt><u>cipher</u></tt>&#8216;, which may take any value from the <a href="http://www.php.net/manual/en/ref.mcrypt.php">mcrypt cipher module list</a>, and which defaults to twofish</li>
<li>&#8216;<tt><u>mode</u></tt>&#8216;, which may take any <a href="http://www.php.net/manual/en/function.mcrypt-list-modes.php">cipher block type</a>, and which defaults to CBC</li>
<li>&#8216;<tt><u>compressor</u></tt>&#8216;, which may take any compressor listed in StonePhpSafeCrypt_compressors.php, and which defaults to off (the package comes with gzip, gzip deflate and bzip2 defined, but you may add others)</li>
<li>&#8216;<u><tt>salt</tt></u>&#8216;, which allows you to override the default salt with a salt of your own choice.</li>
</ul>
<p>All four of these options are reflexive: if you use them during encryption, you must use them identically during decryption, or the process will not allow you to unpack the data.  All functions other than PackCrypt() and UnpackCrypt() in the library are for internal support, and should not be used directly.</p>
<p>Here&#8217;s a minimalist example, to show you what you&#8217;re doing:</p>
<blockquote><p><tt><strong>require_once('StonePhpSafeCrypt.php');</strong></tt></p>
<p><tt><strong>$sourcedata = array('Hello', 1, 2, 3=&gt;4, 'Goodbye');<br />
$packed     = PackCrypt($sourcedata, 'Password');<br />
</strong></tt></p>
<p><tt><strong>if ($packed['state'] === false) { die('Error: ' . $packed['reason']); }<br />
</strong></tt></p>
<p><tt><strong>echo 'Packed: ', $packed['output'], '&lt;br /&gt;';<br />
</strong></tt></p>
<p><tt><strong>$unpacked = UnpackCrypt($packed, 'Password');<br />
echo 'Unpacked: ', print_r($unpacked);<br />
</strong></tt></p></blockquote>
<p>And that&#8217;s all there is to it.  <img src='http://fullof.bs/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<h1>The Fundamentals</h1>
<p>The first thing we need is a way to wrap the encryption and decryption process, without actually forcing a choice of which method is used.  This is important because some machines may not have some algorithms available, because algorithms get broken and replaced, and so on.  The user really needs to be able to select the algorithm.  Even so, the actual process of encryption is fairly ridiculously cumbersome, and can be wrapped.</p>
<p>That said, there&#8217;s a lot to PHP.  One thing that&#8217;s really nice about PHP is its automatic data munging.  Of particular utility is the concept of serialization; objects even have a magic stub they can provide to implement serialization magically.  It can be argued that a high quality wrapper for encryption should magically handle the packing and unpacking of a PHP data type, be it a scalar, an array or even a correctly made object.  Serialize is the appropriate means by which to do so, and so we&#8217;ll build that into our encryptor.</p>
<p>Another important thing for an encryption wrapper is that the user shouldn&#8217;t actually need to know a whole lot to use it safely.  The actual data to be packed and the password by which to do so are sort of common-sense minimums; ideally, a function should be flexible enough to allow more customization, but should require nothing more than these and still be safe.  Importantly, this function <em><strong>must not</strong></em> require the user to know how to make safe passwords.  We will do that for them.  In order to keep that mindset, we will begin referring to two passwords: the user&#8217;s password, which we&#8217;ll call the Weak Key, and the password we derive therefrom, called the Strong Key.  Only the strong key is reliable, or used in any way in the transmitted cipher.  (Weak keys are still subject to social engineering attacks, so end users should still be advised of rules they refuse to follow, but this at least protects the data stream itself.)</p>
<p>To that end, we will create two basic functions: PackCrypt() and UnpackCrypt().  These functions will take two mandatory and two optional arguments each: the data, the weak password, and if the user wants to, they may also override the default choice of encryption algorithms (which is something best reserved for those who are familiar with the advantages and disadvantages of the various algorithms.)</p>
<h2>The workhorses: PackCrypt() and UnpackCrypt()</h2>
<p>PackCrypt and UnpackCrypt are the two functions you actually use in this library.</p>
<h3>PackCrypt(&amp;$Data, &amp;$WeakKey, $options)</h3>
<p>PackCrypt takes any serializable data structure for $Data, any string for $WeakKey, and if you like, some extra commands in $options. $Data can be a nested array full of objects, all sorts of creepy stuff, whatever.  If it&#8217;s a correct and complete PHP class which follows the rules for <a href="http://www.php.net/serialize">serialize()</a>, then it should be safe for PackCrypt().</p>
<p>It&#8217;s really just that simple. Make some horribly complex data structure, and do</p>
<blockquote><p><tt>$packed = PackCrypt($someData, 'my key sucks');</tt></p></blockquote>
<p>and then look at $packed['output'].  Bang: safe, clean serialized secure encryption.</p>
<h3>Why $packed['output']?  Why not just $packed?</h3>
<p>This library (like most of John&#8217;s libraries) returns a state tuple for its operations.  This is a behavior that&#8217;s common in some languages, particularly Erlang/OTP, and which PHP can support quite easily.  It&#8217;s also a very important and powerful technique: it makes concurrent message tracking very easy, it makes keeping track of parallel error states very easy, and it makes complex returns with ancillary information not only possible but quite natural.</p>
<p>PackCrypt returns an array with ['status'], ['reason'] and ['output'] set.  Status is a boolean which represents whether things proceeded correctly.  Reason is a textual description which explains what error set status to <strong>false</strong> when something broke; if status is <strong>true</strong>, which is to say if things went well, it just says &#8220;Successfully encrypted.&#8221; or whatever is appropriate.  Output contains the actual results, or <strong>false</strong> if something failed.</p>
<ul>
<li>If everything goes correctly,</li>
<ul>
<li>['status'] will be <strong>true</strong>,</li>
<li>['output'] will contain your encrypted result, and</li>
<li>['reason'] will say &#8216;Successful Pack&#8217;.</li>
</ul>
<li>If there is a problem,</li>
<ul>
<li>['status'] will be <strong>false</strong>,</li>
<li>['output'] will be <strong>false</strong>, and</li>
<li>['reason'] will contain a message explaining the problem, which will most likely be that the encryption algorithm chosen or the compressor chosen is unavailable on this system</li>
</ul>
</ul>
<h3>Okay, so how does it work</h3>
<p>It&#8217;s fairly straightforward.  First, the functions unpack and apply the options, check for the existance of the requested compressor and so on.  Once that&#8217;s done, the compressor opens the cipher module (such as Blowfish, RSA, Rijndael, TripleDES and so on,) engages the appropriate block cipher mode (cbc, cfb, ecb or ofb,) creates a salted MD5 hash of the weak key, generates a randomized initialization vector, ciphers the IV with a resalted strong key, serializes the incoming data, compresses the serialized data if requested, encrypts the serialized data, writes out the result array and cleans up.  Unsurprisingly, the unpacking scheme is basically the same thing in reverse.<br />
The thing is, you have to know all the steps in order, and you have to do them correctly, accomodating for the different sizes in each algorithm and platform implementation, trim extra space and so on.  So, wrap &#8216;em up, no problem, done.  Welcome to PackCrypt() territory.</p>
<h2>Safe IV Transfer: BlockScramble() and BlockDescramble()</h2>
<p>The PHP manual incorrectly states that the initialization vector for an encrypted datastream may be transmitted plaintext.  This would be highly convenient and provides a desirable mechanism for transfer, but can be the source of man-in-the-middle attacks in CBC block mode algorithms, as well as several other situations.  See <a href="http://www.ciphersbyritter.com/GLOSSARY.HTM#IV">Ciphers by Ritter</a> for a detailed explanation of the problem.  This library solves the problem by salted hashing the weak key and then reversibly merging that with the IV, so that the leading block can be transmitted safely as a stream prefix.</p>
<p>The functions which perform this salting, hashing and merging are called BlockScramble() and BlockDescramble().</p>
<h2>Convenient compression: $options['compressor']</h2>
<p>Of course, one thing that&#8217;s really helpful to have in this kind of routine is inline compression.  Compression both makes the original stream harder to detect and (obviously) reduces bandwidth and storage costs.  However, the way to apply compression to the encryption stream is inobvious; most people would just try compressing the results of the encryption, and that&#8217;s not going to work.  The reason is that compression and encryption are at ends: compression relies on patterns in data, whereas the purpose of encryption is to hide patterns in data.  A well encrypted string when compressed is generally larger than uncompressed.</p>
<p>As such, to keep things simple, I put compression directly into the mechanism, in a way that can be extended to new compression algorithms later (though I have a hard time imagining needing to replace BZip2.)  However, if you want to add support for the latest greatest algorithm, even if it&#8217;s newer than my library, well, no problem.  Open StonePhpSafeCrypt_compressors.php and add your compressor to the list.  Instructions are in the file, but it&#8217;s really quite trivial.</p>
<h2>Subdirectories and require_once()</h2>
<p>Because of the way PHP inclusion works, the require directives in a given script are referential to the including script&#8217;s location, rather than their own.  That means that the includes for the various parts of this library need to be referenced according to their own directory.  If you just dump all the files in the same directory as your main project, well great, works fine.  If you want to put them in a subdirectory, do the following <strong><u>before</u></strong> you include the library (or it will fail in a fairly unreadable way):</p>
<blockquote><p><tt>define('STONE_PHP_SAFE_CRYPT_HOST_DIRECTORY', 'dirgoeshere/');</tt></p></blockquote>
<p>The directory may be absolute or referential, should be in Unix directory format, and needs the trailing slash.</p>
<h1>That&#8217;s it?</h1>
<p>That&#8217;s it.  Unpack the files, set the salt, <tt>$foo = PackCrypt(data, key, options);</tt> and look in $foo['output'].  Safe, convenient and reliable.  This is what it should have been all along.</p>
<p>In case you missed it earlier, <a href="http://sc.tri-bit.com/outgoing/StonePhpSafeCrypt.zip">get the source here</a>.  There is a working example in test.php, but here&#8217;s that same fairly minimalist example again, now that you know what it&#8217;s doing:</p>
<blockquote><p><tt><strong>require_once('StonePhpSafeCrypt.php');</strong></tt></p>
<p><tt><strong>$sourcedata = array('Hello', 1, 2, 3=&gt;4, 'Goodbye');<br />
$packed     = PackCrypt($sourcedata, 'Password');<br />
</strong></tt></p>
<p><tt><strong>if ($packed['state'] === false) { die('Error: ' . $packed['reason']); }<br />
</strong></tt></p>
<p><tt><strong>echo 'Packed: ', $packed['output'], '&lt;br /&gt;';<br />
</strong></tt></p>
<p><tt><strong>$unpacked = UnpackCrypt($packed, 'Password');<br />
echo 'Unpacked: ', print_r($unpacked);<br />
</strong></tt></p></blockquote>
<p>And that&#8217;s all there is to it.  <img src='http://fullof.bs/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://fullof.bs/stone-php-safecrypt-convenient-secure-and-typesafe-encryption-tutorial-library-and-test-code/feed/</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>Stupid Sudoku Book Generator</title>
		<link>http://fullof.bs/stupid-sudoku-book-generator/</link>
		<comments>http://fullof.bs/stupid-sudoku-book-generator/#comments</comments>
		<pubDate>Thu, 26 Jan 2006 08:06:35 +0000</pubDate>
		<dc:creator>John Haugeland</dc:creator>
				<category><![CDATA[FPDF]]></category>
		<category><![CDATA[My Stores]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Puzzles]]></category>
		<category><![CDATA[Sudoku]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[generator]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[store]]></category>

		<guid isPermaLink="false">http://blog.sc.tri-bit.com/?p=16</guid>
		<description><![CDATA[I&#8217;m looking for beta participants for my PC client! See http://blog.sc.tri-bit.com/archives/151. The problem? PDF. The solution? FPDF, PHP, and the force of anger incarnate. So, I&#8217;ve got the puzzle drafting application up and running in a non-painful way, which took no small (read: Herculean) effort and a pinch or two of CSS Ninja Magic. This [...]]]></description>
			<content:encoded><![CDATA[<p><strong>I&#8217;m looking for beta participants for my PC client!</strong> See <a href="http://blog.sc.tri-bit.com/archives/151">http://blog.sc.tri-bit.com/archives/151</a>.</p>
<p>The problem? PDF. The solution? <a title="FPDF, a free PHP script to generate PDFs" href="http://www.fpdf.org/">FPDF</a>, <a title="PHP, the scriptiest scripting language all week" href="http://php.net/">PHP</a>, and the force of anger incarnate.</p>
<p><span id="more-51"></span><br />
So, I&#8217;ve got the puzzle drafting application up and running in a non-painful way, which took no small (read: Herculean) effort and a pinch or two of CSS Ninja Magic. This means I have a relatively pleasant interface in which to hand-create my sudoku puzzles, instead of this pencil and paper bullcrap slowing me down.</p>
<p>Of course, I like my puzzles (being an egotist that&#8217;s a given, but let&#8217;s ignore that for now.) As a result, I want to share them with others, preferably for money. The logical choice is a place like <a title="Stone Sudoku - quality Sudoku books and merchandise" href="http://cafepress.com/StoneSudoku/">Cafe Press</a> or Lulu, but they both want books kind of already laid out, so they can just print them and be done with them.</p>
<p>This all sounds perfectly reasonable, until that horrible death knell comes gonging around the dark recesses of your animal hindbrain, into places your soul is afraid to go, where ancestral memory remembers stuff like <a title="Down With ELM" href="http://java.com/">dinosaurs</a> and being <a title="Bird Flew" href="http://www.usatoday.com/tech/science/discoveries/2006-01-12-human-ancestors-birds_x.htm">hunted by eagles</a> and <a title="Truman's the Mack" href="http://www.amazon.com/gp/product/0671869205/qid=1138261744/sr=8-1/ref=pd_bbs_1/104-2388795-5819116?n=507846&amp;s=books&amp;v=glance">effective presidents</a> and other scary relics of an antiquarian past.</p>
<p>The name of that knell? PDF.</p>
<p>So, in order to provide content for these places, one has to give up a standardized-ish format which is designed for print. Luckily, postscript doesn&#8217;t really much exist in modern tools, so god forbid I be able to go in with a programming language for my layout application, guns a-blazing. (Interject here with fond memories of my father showing me Display PostScript on his NeXTslab as a programming language in which to write actual applications.) At first my plan was to get one of those PDF printer targets like <a title="Primo PDF - a free printer driver that targets PDF" href="http://www.primopdf.com/">Primo</a> going, then to use Word automation from Delphi to do the actual printing. That worked well enough for my blank boards, but it got hella cumbersome when I wanted to do non-trivial boards, so I started to look for alternatives.</p>
<p>Then I found <a title="FPDF, a php library for generating PDFs on the fly" href="http://www.fpdf.org/">FPDF</a>, which in many ways rocks. It&#8217;s a PHP class from which you derive classes which implement printing behaviors. You override methods to handle when page breaks might occur (for example, to set up column driven layout, keep some variable off in a corner somewhere, and when FPDF says &#8220;time to page break,&#8221; you override by saying &#8220;No, just move ten inches to the left and back up to the top.&#8221;) The methods to get things done are relatively straightforward, measured in user-chosen units relative to the edges of the current page, and so on. It&#8217;s relatively pleasant, despite a few seriously annoying bugs.</p>
<p>Granted, it seems either that FPDF only implements a subset of PDF, or that PDF is entirely simpler than I had previously believed. Really, you just have a few graphics primitives with simple color and thickness controls for line and fill, the ability to place form elements and the ability to place images. That&#8217;s pretty much it, and that surprised me.</p>
<p>But, you know what? That&#8217;s all I need for Sudoku. My generation tool now knows how to crap out a homebrew sudoku format (including for all those purty variants I&#8217;ve learned about,) and I have a PHP script that turns many instances of that format straight into CafePress ready books. (Actually, with some tweaking, I intend to extend this script to handle other puzzle types, too. I&#8217;ve got a genuinely funktronic layout model going on, which I&#8217;m getting fairly into.)</p>
<p>So, some standard Sudoku books are on the Very Near Horizon™, as soon as I teach my generator how to put together title pages and instructions pages (there&#8217;s a lot of automatic scaling and placement going on, so that&#8217;s not as trivial as it sounds) and to place some niceties in the books. You&#8217;ll need to <a title="Stone Sudoku - purveyors of fine Sudoku books and merchandise" href="http://cafepress.com/StoneSudoku">buy one</a> to find out what those nicities are, natch.</p>
<p>Right now, my book generator only knows how to draw standard and off-rectangle sudoku (3&#215;3, 4&#215;4, 2&#215;5, et cetera.) Soon, irregular backgrounds. Afterwards, disjoint backgrounds. Promptly following? &#8221;The World&#8221;.</p>
<p>I have some very neat things I intend to reveal on that store in the near future. Be sure to go <a title="Stone Sudoku - your number one source for su doku and nanpure puzzles, books, shirts and merchandise" href="http://cafepress.com/StoneSudoku">buy things</a>. Right now.</p>
]]></content:encoded>
			<wfw:commentRss>http://fullof.bs/stupid-sudoku-book-generator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

