<?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>TechKnack &#187; php</title>
	<atom:link href="http://techknack.net/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://techknack.net</link>
	<description>The rantings of a techie</description>
	<lastBuildDate>Thu, 24 Dec 2009 19:53:49 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PHP Socket Implementation and Webpage Downloader</title>
		<link>http://techknack.net/php-socket-implementation-and-webpage-downloader/</link>
		<comments>http://techknack.net/php-socket-implementation-and-webpage-downloader/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 04:09:12 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=294</guid>
		<description><![CDATA[This post reveals two handy PHP constructs I&#8217;ve been using for a while now: a Socket class and a webpage-downloading function.
The files:

Socket.php (highlighted; plaintext)
webpage.php (highlighted; plaintext)

What good is a full-on Socket class and function, you may ask, when you can simply run file_get_contents with allow_url_fopen turned on?  Well, consider that you want to send [...]]]></description>
			<content:encoded><![CDATA[<p>This post reveals two handy PHP constructs I&#8217;ve been using for a while now: a Socket class and a webpage-downloading function.</p>
<p>The files:</p>
<ul>
<li>Socket.php (<a href="/examples/source_highlighted.php?file=phpwebpage/Socket.php">highlighted</a>; <a href="/examples/source_plaintext.php?file=phpwebpage/Socket.php">plaintext</a>)</li>
<li>webpage.php (<a href="/examples/source_highlighted.php?file=phpwebpage/webpage.php">highlighted</a>; <a href="/examples/source_plaintext.php?file=phpwebpage/webpage.php">plaintext</a>)</li>
</ul>
<p>What good is a full-on Socket class and function, you may ask, when you can simply run file_get_contents with allow_url_fopen turned on?  Well, consider that you want to send specific headers to the server, to POST data for example.  Also, there are other uses for a Socket class than webpage downloading; I use this Socket implementation in a PHP-based IRC bot that I run (by the name of ecode on the Freenode network).  You can use the socket to interact with many different servers.</p>
<h3>Socket</h3>
<p>The Socket class essentially encapsulates PHP&#8217;s socket_* functions, making it easy and straightforward to make a TCP connection with a server.  The socket is given a timeout period in microseconds; while I&#8217;m not 100% sure what this means, I do know that it emulates a sort of &#8220;busy wait&#8221; while waiting for content, allowing applications to do processing while waiting for data to come in through the pipe.</p>
<p>To use the socket, include the Socket.php file and create a variable to hold a new Socket.</p>
<pre class="brush: php;">
require_once(&quot;Socket.php&quot;);

$s = new Socket(1000);
</pre>
<p>The Socket will automatically set up the outgoing TCP socket for usage.  The parameter passed to the new socket (1000 in this case) is the microsecond timeout &#8212; this can be left blank if you wish.</p>
<p>Once created, the socket can connect to any service through the connect() function.  The function takes two arguments: host and port.  Both parameters are optional to allow reuse of the connection; if called without parameters, the Socket will establish a new connection using a host and port from the last connection.  The host is the address you would ping to see if the servers are up &#8212; for example, either google.com or 74.125.67.100, the Socket doesn&#8217;t care which as long as it&#8217;s a server it can connect to.  The port is optional: if you specify a port number, that will be used; if no port number is specified, it attempts to extract a port number from the host (for example, if you used google.com:80); failing that, it will use the last port number specified (default of 80).</p>
<p>Once connected, you can use the send() and get() functions to &#8212; you guessed it &#8212; send() and get() data.  The send function takes a string parameter, the message to be sent, sends the message through socket_write, and returns the value returned by socket_write (the number of bytes successfully sent through the socket).  The get function takes an array parameter to specify fetching options: line (boolean) and length (integer).  If line is set to true, then get will fetch one character at a time until a newline (\n) is encountered and return the line along with any trailing carriage returns (\r) and newlines (\n).  If length is specified as greater than 0, get will fetch one character at a time until the specified number of characters have been read.  If neither is specified, the function will read and return the next 512 characters.  Of course, all cases will terminate if the end of data has been reached.</p>
<p>As a quick example, this portion uses the previously created socket to download the HTTP response headers from google.com&#8217;s homepage:</p>
<pre class="brush: php;">
if ($s-&gt;connect(&quot;www.google.com&quot;, 80)) {
    $get;
    $s-&gt;setVerbose(false);
    $s-&gt;send(&quot;GET / HTTP/1.1&quot;);
    $s-&gt;send(&quot;Host: www.google.com&quot;);
    $s-&gt;send(&quot;&quot;);

    $response = &quot;&quot;;
    while (strpos($response, &quot;\r\n\r\n&quot;)===false) {
        $response .= $s-&gt;get(array(&quot;line&quot;=&gt;true));
    }
}
</pre>
<p>The Socket supports logging and verbosity functions.  The setLog function takes a boolean (true/false for logging) and a string (filename to log to).  The setVerbose function takes only a boolean (true/false &#8212; default false &#8212; for printing out extra information to the console).</p>
<p>Finally, when you&#8217;re finished with the connection, you can call the disconnect() function to cleanly sever the connection.</p>
<h3>webpage()</h3>
<p>The webpage function takes three parameters: a url, a headers array, and a &#8220;headers only&#8221; flag.  The url is simple enough; this is the full url that you want to fetch, including both the host name and the file path (and, optionally, a port number after the hostname).  The headers array goes two ways; you can pass in headers to send and you&#8217;ll get back any headers received.  The headers only flag specifies whether or not to fetch the content of the page; if not, it saves the time of downloading that content, and leaves you with only the response headers.</p>
<p>The headers parameter is two-way, as I mentioned.  You can pass in an associative array of header-name => header-value pairs, which will be formatted properly and sent to the server along with the HTTP request.</p>
<pre class="brush: php;">
$h = array(
    &quot;User-Agent&quot; =&gt; &quot;PHP-webscraper/1.0 php/5&quot;,
    &quot;Authorization&quot; =&gt; &quot;Basic &quot;.base64_encode(&quot;username:password&quot;)
);
$page = webpage(&quot;http://twitter.com/statuses/mentions.json&quot;, $h);
</pre>
<p>The above will send the User-Agent, for identification, and Authorization, to login, headers to the Twitter API, fetching any tweets that mention the user name &#8220;username&#8221; (using the password &#8220;password&#8221;).  The response will be in JSON, and will require extra processing, but this will get you the data.  For more information on HTTP headers, check out the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">HTTP 1.1 RFC, section 14</a>.</p>
<p>Once the page is received from the server, the headers array you passed in will be overwritten by the server&#8217;s response headers, which you can then examine with external code.  With this method, you can also pass in a simple empty array, which will then be populated with the response headers.</p>
<p>The third parameter to the webpage function is simple enough.  Pass true if you want to receive only the server&#8217;s response headers, cutting off the response once those have been received; a blank string will be returned from the function.  Pass false (or no third parameter) if you wish to receive the entire page, the contents of which will be returned as a string.</p>
<p>With these two files (and, of course, the PHP constructs they define), you can download any webpage you would have access to with your browser, provided you are able to use sockets on your server.  Need to scrape some data from a page?  Download that page and apply some regexes to the content.  HTTP Auth required?  No problem, send an extra header with your creds.  The function could also be modified to POST data to a page, or even download and save images and other media; however, those functions will be left as an exercise for the reader.</p>
<img src="http://techknack.net/?ak_action=api_record_view&id=294&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/php-socket-implementation-and-webpage-downloader/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Templating: Variable Date</title>
		<link>http://techknack.net/php-templating-variable-date/</link>
		<comments>http://techknack.net/php-templating-variable-date/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 01:38:55 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[blogs]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=282</guid>
		<description><![CDATA[In building a template system, you may want some way to inject date info using a timestamp (perhaps generated through mktime() ) and date().  But you don&#8217;t want the format to be dependent on the template parser, but rather specified through the variable in the template itself.

$template = preg_replace(
    &#34;#\%date(\:\s*(.*?))?\%#ei&#34;,
  [...]]]></description>
			<content:encoded><![CDATA[<p>In building a template system, you may want some way to inject date info using a timestamp (perhaps generated through mktime() ) and date().  But you don&#8217;t want the format to be dependent on the template parser, but rather specified through the variable in the template itself.</p>
<pre class="brush: php;">
$template = preg_replace(
    &quot;#\%date(\:\s*(.*?))?\%#ei&quot;,
    &quot;date(('\\2'!=\&quot;\&quot;?'\\2':\$date_format), \$timestamp)&quot;,
    $template
);
</pre>
<p>This falls on the &#8220;advanced&#8221; side of intermediate, I would think, so here&#8217;s an explanation:</p>
<p>This is a standard preg_replace($pattern, $replacement, $source_string).  What we want to do is replace the variable %date% in $template with a date string generated from $timestamp.  But %date% is too limiting; within the template, we&#8217;d like to write something like %date: F j, Y% to get a date like &#8220;March 12, 2009,&#8221; or any other format.</p>
<p>The regular expression is like so: <strong>#\%date(\:\s*(.*?))?\%#ei</strong>.  The &#8220;hashes&#8221; (#) here act as delimiters for the regex; the <em>e</em> and <em>i</em> after the second hash turn on &#8220;eval&#8217;d replacement&#8221; and &#8220;case-insensitivty&#8221;, respectively (<a href="http://us.php.net/manual/en/reference.pcre.pattern.modifiers.php">learn more about PCRE regex modifiers at php.net</a>).  So the regex to deal with is <strong>\%date(\:\s*(.*?))?\%</strong>.  The <strong>\%</strong> are the markers for our template variables; <strong>date</strong> is the name of the variable to look for.  <strong>(\:\s*(.*?))?</strong> matches zero or one instances of our &#8220;variable modifier&#8221;: a colon, followed by any amount of whitespace (including none), followed by any number of any characters (where the extra <strong>?</strong> makes the <strong>.*</strong> &#8220;non-greedy&#8221;; it&#8217;ll stop &#8220;eating&#8221; characters when it reaches the next percent sign).  For preg_replace, this will place our date() format in &#8220;\\2&#8243; if it is present; if it is not present, &#8220;\\2&#8243; will not be set.</p>
<p>The replacement is as follows: <strong>&#8220;date((&#8217;\\2&#8242;!=\&#8221;\&#8221;?&#8217;\\2&#8242;:\$date_format), \$timestamp)&#8221;</strong>.  preg_replace will insert the matched date format from the regex into every occurrence of &#8220;\\2&#8243; in the replacement string, and then run eval() on the resulting string to get the replacement value (all thanks to the <em>e</em> modifier in the regex).  Assuming our regex matched &#8220;F j, Y&#8221; as the match, we&#8217;ll get <strong>&#8220;date((&#8217;F j, Y&#8217;!=\&#8221;\&#8221;?&#8217;F j, Y&#8217;:\$date_format), \$timestamp)&#8221;</strong>.  The <strong>(&#8217;F j, Y&#8217;!=\&#8221;\&#8221;?&#8217;F j, Y&#8217;:\$date_format)</strong> part chooses the date format; if the match is not set (ie, an empty string), use whatever is in the variable $date_format; else, if the date format was matched, use it.  This allows us to use %date% in the template, to default to a server-side specified format.</p>
<p>And there it is.  You can now put &#8220;%date: F j, Y%&#8221; in your template, and it will be expanded to &#8220;March 12, 2009&#8243; (depending on the actual date, of course <img src='http://techknack.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ).  That is, if your templating system works in the first place&#8230;</p>
<img src="http://techknack.net/?ak_action=api_record_view&id=282&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/php-templating-variable-date/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Method for CSS Variables</title>
		<link>http://techknack.net/a-method-for-css-variables/</link>
		<comments>http://techknack.net/a-method-for-css-variables/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 21:33:57 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=279</guid>
		<description><![CDATA[Jay Salvat at nettuts has written an article on adding variables to your css files.  I like the approach, which includes caching the results, though the code presented is not 100% secure, as commenter Pelle has noted.
As for the most popular response, having apache run css files as php code, there are a few [...]]]></description>
			<content:encoded><![CDATA[<p>Jay Salvat at <a href="http://net.tutsplus.com">nettuts</a> has written an article on <a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/">adding variables to your css files</a>.  I like the approach, which includes caching the results, though the code presented is not 100% secure, as <a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/#comment-45724">commenter Pelle</a> has noted.</p>
<p>As for the most popular response, having apache run css files as php code, there are a few issues that come to mind that the article&#8217;s approach takes care of: caching, cleanliness, and portability.</p>
<p>Caching, as the author notes, reduces the number of CPU cycles the server must devote to php processing of the css files.  The parser also implements HTTP features for determining if the file has been modified and needs reloading.  Simply setting the server to parse CSS files, you may or may not lose these features, depending on your server settings.</p>
<p>The method is also clean; using a parsing class lets you put simple variable assignments directly in the CSS file.  Associating CSS with the PHP parser requires you to use the PHP tags and all the appropriate PHP markers ( &lt;?php $var = &#8220;whatever&#8221;; ?&gt; ); if you miss a semicolon, a quote, a dollar sign, or any other part of the required &#8220;PHP syntax&#8221;, your css file at best will contain a php error or warning message, making the code invalid, or at worst will not display at all, giving a blank css file.  The parser Jay gives, while requiring a syntax of its own, is much simpler to use.</p>
<p>Jay&#8217;s solution is portable; the only server configuration necessary is enabling apache&#8217;s mod_rewrite module, which should be enabled anyway.  If that is done, you can move the .htaccess and enhanced_css.php files to any server, and it will work without further server config.</p>
<p>As commenter Pelle notes, however, if someone knows you&#8217;re using this method and they know the path to your enhanced_css.php file, they could use it maliciously.  Jay responds with a quick fix that makes sure the class only parses files ending with &#8220;css&#8221;, but I believe that further security could be provided, though I&#8217;ve not taken the time to analyze the code enough to make suggestions.</p>
<p><a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/#comment-45795">Chris Pratt</a> made a suggestion of changing the parser to hunt out <a href="http://disruptive-innovations.com/zoo/cssvariables/#mozTocId992035">CSS variables as proposed by Daniel Glazman and David Hyatt</a>.  I thought this would be a good idea; the syntax proposed in that doument is much more like the CSS3 stuff we&#8217;re slowly getting used to, such as :not() and attr().</p>
<p>For those interested, you could read <a href="http://www.w3.org/People/Bos/CSS-variables">why some think CSS variables are harmful</a>.</p>
<img src="http://techknack.net/?ak_action=api_record_view&id=279&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/a-method-for-css-variables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Couple Little PHP Array Tricks</title>
		<link>http://techknack.net/a-couple-little-php-array-tricks/</link>
		<comments>http://techknack.net/a-couple-little-php-array-tricks/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 19:52:51 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[asides]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=252</guid>
		<description><![CDATA[Maintaining array indexes after deleting an element; selecting a random element from an associative array.]]></description>
			<content:encoded><![CDATA[<p>To delete an item from an array:</p>
<pre class="brush: php;">
unset($array[$i]);
</pre>
<p>However, this will break a &#8220;for ($i=0; $i&lt;count(); $i++)&#8221; loop.  To maintain sequential indexes:</p>
<pre class="brush: php;">
$array = array_values($array);
</pre>
<p>This will reset the indexes; beware, though, the items may not be in the same order afterwards.</p>
<p>To select a random item from an associative list:</p>
<pre class="brush: php;">
$array = array(
    &quot;one&quot;=&gt;1,
    &quot;two&quot;=&gt;2,
    &quot;three&quot;=&gt;3
);
$keys = array_keys($array);
$index = $keys[rand()%count($keys)];
$random = $array[$index];

// or, more compactly:

$k = array_keys($array);
$random = $array[$k[rand()%count($k)]];
</pre>
<img src="http://techknack.net/?ak_action=api_record_view&id=252&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/a-couple-little-php-array-tricks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rounded Corners at the Src</title>
		<link>http://techknack.net/rounded-corners-at-the-src/</link>
		<comments>http://techknack.net/rounded-corners-at-the-src/#comments</comments>
		<pubDate>Sun, 08 Feb 2009 22:57:57 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=242</guid>
		<description><![CDATA[CSS-based rounded corner solutions are excellent for website layouts, but it&#8217;s just downright silly to envelope a single img tag with two to four extraneous divs just to get some nice rounded corners on that one image.  PHP (with its GD library) is excellent for this purpose.

Image: Warped by ~eternicode (me).
My PHP script can [...]]]></description>
			<content:encoded><![CDATA[<p>CSS-based rounded corner solutions are excellent for website layouts, but it&#8217;s just downright silly to envelope a single img tag with two to four extraneous divs just to get some nice rounded corners on that one image.  PHP (with its GD library) is excellent for this purpose.</p>
<p><img alt="Example image without rounded corners." src="http://th00.deviantart.com/fs26/300W/i/2008/094/b/a/Warped_by_eternicode.png" style="float:left;" /><img alt="Example image using the PHP rounded corners script." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs26/300W/i/2008/094/b/a/Warped_by_eternicode.png" title="Example image using the PHP rounded corners script." style="float:right" /></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Warped-81839030">Warped</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a> (me).</p>
<p>My PHP script can take any jpg, png, or static gif image (supplied through the &#8220;src&#8221; GET variable) and apply rounded corners to them.  The space left by the corners is transparent, and so blends in with any background you may have applied to your content section.</p>
<p>Using GET variables, you can control various aspects of the output image.  Using &#8220;rad&#8221; or &#8220;radius&#8221;, you can increase and decrease the size of the corners.  The default value for the radius is 20, which I&#8217;ve found to be reasonable for most images.</p>
<p><img alt="Original image." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs23/300W/i/2007/350/4/4/Let_It_Shine_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using radius option." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs23/300W/i/2007/350/4/4/Let_It_Shine_by_eternicode.png&#038;radius=40" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Let-It-Shine-71549321">Let It Shine</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>Using &#8220;width&#8221; or &#8220;height&#8221;, you can scale down the image to meet your needs &#8212; the specified width or height will be taken as the maximum width or height, in pixels, and the aspect ratio will be maintained.  If both height and width are given, the smallest result of the two possible outputs will be used.</p>
<p><img alt="Original image." src="http://th04.deviantart.com/fs24/300W/i/2007/350/4/3/Minty_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using width option with value of 300." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th04.deviantart.com/fs24/300W/i/2007/350/4/3/Minty_by_eternicode.png&#038;width=250" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Minty-72269137">Minty</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>There is also a &#8220;squarification&#8221; option, which will reduce either the width or height (whichever is largest) to produce a squared image.  If &#8220;squared&#8221; is specified as true, radius and scaling will take effect as normal, using the new squared aspect ratio in place of the old ratio.</p>
<p><img alt="Original image." src="http://th02.deviantart.com/fs17/300W/i/2007/218/8/3/Convergence_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using squared option." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th02.deviantart.com/fs17/300W/i/2007/218/8/3/Convergence_by_eternicode.png&#038;squared=true" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Convergence-61635157">Convergence</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>The final option, which was kind of an afterthought, is the &#8220;format&#8221; option &#8212; you can choose either &#8220;png&#8221; or &#8220;gif&#8221; as the output format.  I only added this because with png format, in IE6, the method I used would produce magenta-colored corners, rather than transparent colors.  Supplying a gif output fixes this problem for IE6, though the png option is generally preferred.</p>
<p>The source of the script is very well documented, but feel free to ask questions if I missed something.<br />
<a href="http://techknack.net/examples/phprounded/">The example directory.</a><br />
<a href="http://techknack.net/examples/phprounded/irrcos.php?src=Rekindled_by_eternicode.jpg">Active script</a> using a local image, for your experimentation (any other image can be specified through &#8220;src&#8221;).<br />
<a href="http://techknack.net/examples/phprounded/source_highlighted.php">Highlighted script source.</a><br />
<a href="http://techknack.net/examples/phprounded/source_plaintext.php">Plain text script source.</a></p>
<img src="http://techknack.net/?ak_action=api_record_view&id=242&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/rounded-corners-at-the-src/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Installing OCI8 for PHP</title>
		<link>http://techknack.net/installing-oci8-for-php/</link>
		<comments>http://techknack.net/installing-oci8-for-php/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 04:49:31 +0000</pubDate>
		<dc:creator>eternicode</dc:creator>
				<category><![CDATA[databases]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://techknack.net/?p=198</guid>
		<description><![CDATA[I recently had a project that required me to connect to a remote Oracle 10g database from my local server using a PHP-based client, the problem being that the default PHP install has no libraries for working with Oracle.  Fortunately, Oracle has released binaries for their OCI, or Oracle Call Interface, for Linux systems.
Once [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had a project that required me to connect to a remote Oracle 10g database from my local server using a PHP-based client, the problem being that the default PHP install has no libraries for working with Oracle.  Fortunately, Oracle has released binaries for their OCI, or Oracle Call Interface, for Linux systems.</p>
<p>Once you have these binaries, however, you have to figure out how to integrate them with your system and with PHP.  The fairly concise and complete guide that I came across was <a href="http://en.opensuse.org/Howto_build_oci8_extension_module_for_php">Howto build OCI8 extension module for php</a>.  The catch?  It&#8217;s on the OpenSUSE wiki, and I use Ubuntu server.  Fortunately, the instructions worked very well, regardless of distro differences.  I did, however, discover some things that would make the install process easier, and so I offer up these steps to any pioneering PHP/Oracle developers.  It may be useful to &#8220;sudo su&#8221; for this, as you will otherwise need a lot of sudoing commands:</p>
<ol>
<li>
Download the <a href="http://www.oracle.com/technology/software/tech/oci/instantclient/index.html">Oracle InstantClient</a> binary zips (I used the &#8220;Linux x86&#8243; distribution).  You will need the Basic and SDK packages.  Also, you will need <a href="http://www.bugmenot.com/">an Oracle.com account</a> in order to download the files.
</li>
<li>
Once you&#8217;ve downloaded the files, mkdir (with root privileges) the /opt/oracle directory and unzip the zip files to that directory, as per the OpenSUSE instructions.  You will end up with one directory called &#8220;instantclient_XX_X&#8221;, where &#8220;XX_X &#8220;is the instantclient version number.
</li>
<li>
Inside the instantclient directory, symlink libclntsh.so:</p>
<pre class="brush: bash;">
$ ln -s libclntsh.so.11.1 libclntsh.so
</pre>
<p>I&#8217;m not sure this is necessary, as after I installed OCI8, that file is no longer a symlink.</li>
<li>Install the php5-dev and php-pear packages.</li>
<li>At a command line, run &#8220;pecl search oci&#8221;.  This should return at least one package with a description that reads &#8220;Extension for Oracle Database&#8221;.  Note the package name, and then run &#8220;pecl install {package-name}&#8221;, where {package-name} is the name of the package from your search.
</li>
<li>
As pecl runs about, making sure everything is ready for the oci package, it may notice that you have no ORACLE_HOME environment variable set, and will prompt you for the information:</p>
<pre class="brush: bash;">
root@computer:/opt/oracle# sudo pecl install oci8
downloading oci8-1.3.4.tgz ...
Starting to download oci8-1.3.4.tgz (134,240 bytes)
.............................done: 134,240 bytes
10 source files, building
running: phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519
 1. Please provide the path to the ORACLE_HOME directory. Use 'instantclient,/path/to/instant/client/lib' if you're compiling with Oracle Instant Client : autodetect

1-1, 'all', 'abort', or Enter to continue:
</pre>
<p>This is the tricky part that no one seems to explain very well (and the text of the prompt doesn&#8217;t help at all): that second &#8220;1&#8243; after the &#8220;1-&#8221; is an option.  If you simply enter the path to your instantclient files, pecl will switch to autodetect mode.  However, if you enter &#8220;1&#8243; here, then &#8220;instantclient,/opt/oracle/instantclient_11_1&#8243; at the next prompt (and hit enter at the prompt after that, I don&#8217;t know why it shows up), it should work fine.</p>
<pre class="brush: bash;">
1-1, 'all', 'abort', or Enter to continue: 1
Please provide the path to the ORACLE_HOME directory. Use 'instantclient,/path/to/instant/client/lib' if you're compiling with Oracle Instant Client [autodetect] : instantclient,/opt/oracle/instantclient_11_1
 1. Please provide the path to the ORACLE_HOME directory. Use 'instantclient,/path/to/instant/client/lib' if you're compiling with Oracle Instant Client : instantclient,/opt/oracle/instantclient_11_1

1-1, 'all', 'abort', or Enter to continue: [Enter]
building in /var/tmp/pear-build-root/oci8-1.3.4
running: /tmp/pear/cache/oci8-1.3.4/configure --with-oci8=instantclient,/opt/oracle/instantclient_11_1
checking for ......
</pre>
</li>
<li>
Contrary to the OpenSUSE article, I found no need to set an LD_LIBRARY_PATH variable &#8212; the functions worked just fine without it.
</li>
<li>
Edit the php.ini files as necessary (add the line &#8220;extension=oci8.so&#8221;)
</li>
<li>
I did get an error concerning libaio.so.1:</p>
<pre class="brush: bash;">
PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib/php5/20060613+lfs/oci8.so' - libaio.so.1: cannot open shared object file: No such file or directory in Unknown on line 0
</pre>
<p>Installing packages libaio1 and libaio-dev solved this problem, though I&#8217;m not so sure libaio-dev is necessary.
</li>
<li>
Assuming everything went well, you should be able to use the <a href="http://us2.php.net/manual/en/function.oci-connect.php">PHP OCI8 functions</a> without anything other than &#8220;insufficient arguments&#8221; complaints <img src='http://techknack.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .  And don&#8217;t forget to <a href="http://us2.php.net/manual/en/function.oci-commit.php">oci_commit()</a>!
</li>
</ol>
<p>If I missed anything or am unclear about something, feel free to ask questions.  I&#8217;ve used these steps to successfully set up OCI8 on two separate computers running Kubuntu Hardy and Ubuntu Hardy Server.  OpenSUSE folks should note that the php-pear package may be named php5-pear instead; I don&#8217;t know about the libaio packages.</p>
<img src="http://techknack.net/?ak_action=api_record_view&id=198&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://techknack.net/installing-oci8-for-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
