<?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>v-nessa.net &#187; php</title>
	<atom:link href="http://www.v-nessa.net/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.v-nessa.net</link>
	<description>pink is the new black</description>
	<lastBuildDate>Tue, 20 Jul 2010 13:48:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Simple PHP Script for RBL Checking</title>
		<link>http://www.v-nessa.net/2010/07/16/simple-php-script-for-rbl-checking</link>
		<comments>http://www.v-nessa.net/2010/07/16/simple-php-script-for-rbl-checking#comments</comments>
		<pubDate>Fri, 16 Jul 2010 20:43:59 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=368</guid>
		<description><![CDATA[It&#8217;s useful for ISP&#8217;s and email service providers to run occasional RBL checks against their IPs to know when they are being blacklisted by populate CBL services. I&#8217;ve written a simple script that utilizes the DNSBL pear library to check against common blacklists, when given a list of IPs in a file. First, you need [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F07%2F16%2Fsimple-php-script-for-rbl-checking"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F07%2F16%2Fsimple-php-script-for-rbl-checking&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>It&#8217;s useful for ISP&#8217;s and email service providers to run occasional RBL checks against their IPs to know when they are being blacklisted by populate CBL services. I&#8217;ve written a simple script that utilizes the DNSBL pear library to check against common blacklists, when given a list of IPs in a file.</p>
<p>First, you need to download or install the <a href="http://pear.php.net/package/Net_DNSBL" target="_blank">NET_DNSBL</a> pear module. (Command: <strong>pear install NET_DNSBL</strong>)</p>
<p><code>&lt;?php<br />
require_once('Net/DNSBL.php');</code></p>
<p><code>$iplist = file("/path/to/iplist");</code></p>
<p><code>foreach ($iplist as $ip){</code></p>
<p><code>$dnsbl = new Net_DNSBL();</code></p>
<p><code>$dnsbl-&gt;setBlacklists(array(<br />
'sbl-xbl.spamhaus.org',<br />
'dnsbl.sorbs.net',<br />
'bl.spamcop.net',<br />
'dnsbl-1.uceprotect.net',<br />
'dnsbl-2.uceprotect.net',<br />
'dnsbl-3.uceprotect.net',<br />
'isps.spamblocked.com',<br />
'zen.spamhaus.org'<br />
));</code></p>
<p><code>if ($dnsbl-&gt;isListed($ip)) {</code></p>
<p><code>echo "IP $ip is blacklisted!\n";</code></p>
<p><code>}</code></p>
<p><code>else {<br />
echo "IP $ip not listed\n";<br />
}<br />
}</code></p>
<p><code>?&gt;</code></p>
<p>Of course, this script can be very easily modified to pull IPs from a database, or assign the $ip variable from a GET or POST request (like from a form or API).  Here&#8217;s an exclusive list of some RBL&#8217;s you can check against using this script, by adding them to the array shown:</p>
<blockquote><p>asiaspam.spamblocked.com<br />
bl.deadbeef.com<br />
bl.emailbasura.org<br />
bl.spamcop.net<br />
blackholes.five-ten-sg.com<br />
blacklist.woody.ch<br />
bogons.cymru.com<br />
cbl.abuseat.org    cdl.anti-spam.org.cn<br />
combined.abuse.ch<br />
combined.rbl.msrbl.net<br />
db.wpbl.info<br />
dnsbl-1.uceprotect.net<br />
dnsbl-2.uceprotect.net<br />
dnsbl-3.uceprotect.net<br />
dnsbl.abuse.ch<br />
dnsbl.ahbl.org<br />
dnsbl.cyberlogic.net<br />
dnsbl.inps.de<br />
dnsbl.njabl.org<br />
dnsbl.sorbs.net<br />
drone.abuse.ch<br />
duinv.aupads.org<br />
dul.dnsbl.sorbs.net<br />
dul.ru<br />
dyna.spamrats.com<br />
dynip.rothen.com<br />
eurospam.spamblocked.com<br />
fl.chickenboner.biz<br />
http.dnsbl.sorbs.net<br />
images.rbl.msrbl.net<br />
ips.backscatterer.org<br />
isps.spamblocked.com<br />
ix.dnsbl.manitu.net<br />
korea.services.net<br />
lacnic.spamblocked.com<br />
misc.dnsbl.sorbs.net<br />
noptr.spamrats.com<br />
ohps.dnsbl.net.au<br />
omrs.dnsbl.net.au<br />
orvedb.aupads.org<br />
osps.dnsbl.net.au<br />
osrs.dnsbl.net.au<br />
owfs.dnsbl.net.au<br />
owps.dnsbl.net.au<br />
pbl.spamhaus.org<br />
phishing.rbl.msrbl.net<br />
probes.dnsbl.net.au<br />
proxy.bl.gweep.ca<br />
proxy.block.transip.nl<br />
psbl.surriel.com<br />
rbl.interserver.net<br />
rdts.dnsbl.net.au<br />
relays.bl.gweep.ca<br />
relays.bl.kundenserver.de<br />
relays.nether.net<br />
residential.block.transip.nl<br />
ricn.dnsbl.net.au<br />
rmst.dnsbl.net.au<br />
sbl.spamhaus.org<br />
short.rbl.jp<br />
smtp.dnsbl.sorbs.net<br />
socks.dnsbl.sorbs.net<br />
spam.dnsbl.sorbs.net<br />
spam.rbl.msrbl.net<br />
spam.spamrats.com<br />
spamlist.or.kr<br />
spamrbl.imp.ch<br />
t3direct.dnsbl.net.au<br />
tor.ahbl.org<br />
tor.dnsbl.sectoor.de<br />
torserver.tor.dnsbl.sectoor.de<br />
ubl.lashback.com<br />
ubl.unsubscore.com<br />
virbl.bit.nl<br />
virus.rbl.jp<br />
virus.rbl.msrbl.net<br />
web.dnsbl.sorbs.net<br />
wormrbl.imp.ch<br />
xbl.spamhaus.org<br />
zen.spamhaus.org</p></blockquote>
<p><map name='google_ad_map_368_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/368?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_368_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=368&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F07%2F16%2Fsimple-php-script-for-rbl-checking' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=368&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/07/16/simple-php-script-for-rbl-checking/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using PHP to Perform DNS Lookups</title>
		<link>http://www.v-nessa.net/2010/06/30/using-php-to-perform-dns-lookups</link>
		<comments>http://www.v-nessa.net/2010/06/30/using-php-to-perform-dns-lookups#comments</comments>
		<pubDate>Wed, 30 Jun 2010 16:29:44 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=365</guid>
		<description><![CDATA[PHP has a couple DNS functions you can use to perform record lookups. Most of us are familiar with the two basic ones &#8211; gethostbyname() and gethostbyaddr(), both of which perform a single function &#8211; returning a hostname or IP address. Here&#8217;s an example of both: &#60;?php $ip = gethostbyname("v-nessa.net"); $host = gethostbyaddr("69.174.114.71"); echo "v-nessa.net [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F06%2F30%2Fusing-php-to-perform-dns-lookups"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F06%2F30%2Fusing-php-to-perform-dns-lookups&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>PHP has a couple DNS functions you can use to perform record lookups.</p>
<p>Most of us are familiar with the two basic ones &#8211; <a href="http://us4.php.net/gethostbyname" target="_blank">gethostbyname()</a> and <a href="http://us4.php.net/gethostbyname" target="_blank">gethostbyaddr()</a>, both of which perform a single function &#8211; returning a hostname or IP address. Here&#8217;s an example of both:</p>
<p><code>&lt;?php</code></p>
<p><code>$ip = gethostbyname("v-nessa.net");<br />
$host = gethostbyaddr("69.174.114.71");</code></p>
<p><code>echo "v-nessa.net has the IP $ip, which reverses to $host";</code><br />
<code>?&gt;</code></p>
<p>The above will return:</p>
<blockquote><p>v-nessa.net has the IP 69.174.114.71, which has a PTR of server.v-nessa.net</p></blockquote>
<p>Similarly to gethostbyname, there&#8217;s <a href="http://us2.php.net/manual/en/function.gethostbynamel.php" target="_blank">gethostbynamel</a> which is useful for hostnames with multiple A records:</p>
<p><code>$ips = gethostbynamel("test.v-nessa.net");<br />
foreach ($ips as $ip =&gt; $value){<br />
echo $value . "\n";<br />
}</code></p>
<p>Will return:</p>
<blockquote><p>69.174.114.71<br />
69.174.115.243</p></blockquote>
<p>A more advanced function is <a href="http://us2.php.net/manual/en/function.dns-get-record.php" target="_blank">dns_get_record</a>, which can pull any valid record for a hostname or IP.  Think about the dig command you use in Unix to find DNS records:</p>
<blockquote><p>nessa@nessa-desktop:~$ dig +short v-nessa.net A<br />
69.174.114.71</p></blockquote>
<p>The dns_get_record function works in a similar way, and can obtain the following DNS record types:</p>
<p><strong><tt>DNS_A</tt></strong>, <strong><tt>DNS_CNAME</tt></strong>,        <strong><tt>DNS_HINFO</tt></strong>, <strong><tt>DNS_MX</tt></strong>,        <strong><tt>DNS_NS</tt></strong>, <strong><tt>DNS_PTR</tt></strong>,        <strong><tt>DNS_SOA</tt></strong>, <strong><tt>DNS_TXT</tt></strong>,        <strong><tt>DNS_AAAA</tt></strong>, <strong><tt>DNS_SRV</tt></strong>,        <strong><tt>DNS_NAPTR</tt></strong>, <strong><tt>DNS_A6</tt></strong>,        <strong><tt>DNS_ALL</tt></strong> or <strong><tt>DNS_ANY</tt></strong>.</p>
<p>The following will give you a similar result:</p>
<p><code>$recs = dns_get_record("v-nessa.net", DNS_A);<br />
print_r($recs);</code></p>
<p>Will return:</p>
<blockquote><p>Array<br />
(<br />
[0] =&gt; Array<br />
(<br />
[host] =&gt; v-nessa.net<br />
[type] =&gt; A<br />
[ip] =&gt; 69.174.114.71<br />
[class] =&gt; IN<br />
[ttl] =&gt; 13728<br />
)<br />
)</p></blockquote>
<p>If you want to obtain multiple DNS types, you can do so by separating the record types with a plus sign:</p>
<p><code>$recs = dns_get_record("v-nessa.net", DNS_A + DNS_MX);</code></p>
<p>Will return:</p>
<blockquote><p>Array<br />
(<br />
[0] =&gt; Array<br />
(<br />
[host] =&gt; v-nessa.net<br />
[type] =&gt; A<br />
[ip] =&gt; 69.174.114.71<br />
[class] =&gt; IN<br />
[ttl] =&gt; 13736<br />
)</p>
<p>[1] =&gt; Array<br />
(<br />
[host] =&gt; v-nessa.net<br />
[type] =&gt; MX<br />
[pri] =&gt; 0<br />
[target] =&gt; v-nessa.net<br />
[class] =&gt; IN<br />
[ttl] =&gt; 14145<br />
)</p>
<p>)</p></blockquote>
<p>You&#8217;ll notice that the output is a double array, so to call individual values you can do either of the following:</p>
<p><code>// will return the IP for array 0 ( A record)</code></p>
<p><code>echo $recs[0]['ip'];</code></p>
<p><code>// will return results for common records</code></p>
<p><code>foreach ($recs as $type =&gt; $value){<br />
echo $value[ip] . "\n";<br />
}</code></p>
<p>Similar to the example above, you can use the DNS_ALL type to show any records available for the hostname, and use a minus sign to exclude certain record types. For example, the below code will return all DNS results for v-nessa.net, but exclude NS records:</p>
<p><code>$recs = dns_get_record("v-nessa.net", DNS_ALL - DNS_NS );</code></p>
<p><code>foreach ($recs as $type =&gt; $value){<br />
echo $value[type] . "\n";<br />
}</code></p>
<p>The following records were returned:</p>
<blockquote><p>A<br />
SOA<br />
MX<br />
TXT</p></blockquote>
<p>Here&#8217;s a more practical example &#8211; a simple PHP DNS lookup script. Say you have a form on your site that allows a user to type in a hostname and select a type of record: A, MX, NS, and TXT. The passed form values are $host and $type, and the below script will accept the variables and output the results according to the record type:</p>
<p>HTML Form:</p>
<p><code>&lt;form action="dns.php" method="POST"&gt;<br />
Hostname: &lt;input type="text" name="host" /&gt;<br />
Type: &lt;select name="type"&gt;<br />
&lt;option value="a"&gt;A&lt;/option&gt;<br />
&lt;option value="mx"&gt;MX&lt;/option&gt;<br />
&lt;option value="ns"&gt;NS&lt;/option&gt;<br />
&lt;option value="txt"&gt;TXT&lt;/option&gt; &lt;/select&gt;<br />
&lt;/form&gt;</code></p>
<p>PHP Script (dns.php):</p>
<pre>&lt;?php

if(!empty($_POST['host']) &amp;&amp; !empty($_POST['type'])){

    // Grab variable from form and define valid types

    $host = $_POST['host'];
    $type = strtoupper($_POST['type');
    $validtypes=array("A","MX","NS","TXT");

    // Check that dns type is defined or allowed

    if(!defined("DNS_" . $type) or !in_array($type,$validtypes)){
       echo "Invalid DNS Type!";
    }else{

       $type = constant("DNS_" . $type);
       $rec = dns_get_record($host, $type);

       // Set result types - can be modified by using available elements from $rec array

       switch($type){
             case DNS_A:
                    $recvals=array("Hostname" =&gt; "host","Type" =&gt; "type", "IP" =&gt; "ip");
                    break;
             case DNS_MX:
                    $recvals=array("Hostname" =&gt; "host","Type" =&gt; "type", "Target" =&gt; "target", "Priority" =&gt; "pri");
                    break;
             case DNS_NS:
                    $recvals=array("Hostname" =&gt; "host","Type" =&gt; "type", "Target" =&gt; "target");
                    break;
             case DNS_TXT:
                    $recvals=array("Hostname" =&gt; "host","Type" =&gt; "type", "Record" =&gt; "txt");
                    break;
        }

      // Output results

      foreach ($rec as $arr =&gt; $num){
             foreach ($recvals as $title =&gt; $value){
                    echo $title . " : " . $num[$value] . "\n";
             }
      }

    }
} else {

     echo "Either hostname or record type is missing";
}</pre>
<p>It&#8217;s of course easy to modify the above code accordingly, and I&#8217;m sure there may be better ways to do this. Feel free to post your own code snippets or comments.</p>
<p><map name='google_ad_map_365_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/365?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_365_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=365&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F06%2F30%2Fusing-php-to-perform-dns-lookups' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=365&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/06/30/using-php-to-perform-dns-lookups/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>PHP 5.3: Why We&#8217;re All Late to the Party</title>
		<link>http://www.v-nessa.net/2010/05/27/php-5-3-why-were-all-late-to-the-party</link>
		<comments>http://www.v-nessa.net/2010/05/27/php-5-3-why-were-all-late-to-the-party#comments</comments>
		<pubDate>Thu, 27 May 2010 18:59:13 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=334</guid>
		<description><![CDATA[It&#8217;s been almost a year since the PHP 5.3 branch was released to the PHP community, and yet we&#8217;re all still in the shadow of PHP 5.2.  If you&#8217;re just a faithful customer wondering why your host isn&#8217;t getting with the times, I&#8217;ll tell you exactly why: We don&#8217;t stock enough diapers to keep up [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F27%2Fphp-5-3-why-were-all-late-to-the-party"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F27%2Fphp-5-3-why-were-all-late-to-the-party&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>It&#8217;s been <a href="http://www.php.net/archive/2009.php#id2009-06-30-1" target="_blank">almost a year</a> since the PHP 5.3 branch was released to the PHP community, and yet we&#8217;re all still in the shadow of PHP 5.2.  If you&#8217;re just a faithful customer wondering why your host isn&#8217;t getting with the times, I&#8217;ll tell you exactly why: <em>We don&#8217;t stock enough diapers to keep up with that ish.</em></p>
<p>Let me talk about <em>you</em>, the common website owner, that runs a simple Drupal or WordPress site.  You didn&#8217;t sign up with your host to go around in circles over compatibility problems that could have been avoided by your host doing a little research. As a programmer, I would hold it to any site owner to check their site&#8217;s requirements and the offerings of their host before they unnecessarily waste a lot of time and money, but as a system administrator I frown upon shared hosting providers offering software with known <a href="http://www.v-nessa.net/wp-content/uploads/2010/05/party-hat2.jpg" rel="lightbox"><img class="alignright size-full wp-image-338" title="party-hat" src="http://www.v-nessa.net/wp-content/uploads/2010/05/party-hat2.jpg" alt="" width="100" height="143" /></a>compatibility issues just to be able to advertise as the &#8220;latest and greatest&#8221;. The latest isn&#8217;t always the greatest, and it won&#8217;t be until the community catches up with what the greatest has to offer.</p>
<p>I&#8217;ve had numerous discussions with my superiors about whether to upgrade to PHP 5.3, and the end result is pretty much the same &#8211; <em>we&#8217;re just not ready.</em> And neither are our customers, or the developers of the applications they use.  And trust me &#8211; this is normal. We all went through the same thing when PHP 4.2 came out, and again with PHP 5, and <em>again</em> with PHP 5.2.  That being said, this is why all the good hosts are now also holding off jumping on the PHP 5.3 bandwagon:</p>
<ul>
<li>Lack of compatibility:  Many open source applications and frameworks (such as Drupal, Joomla, Magento, and even parts of WordPress) are not fully compatible with PHP 5.3 yet</li>
<li>No Zend Optimizer or Zend Guard support</li>
<li>It&#8217;s not required for PCI compliance yet, which is one of the main reasons why hosts upgrade PHP on their servers</li>
</ul>
<p>PHP 5.3 does have a lot of new features and functions to offer, and it will eventually wiggle its way into mainstream hosting -  it&#8217;s just not ready for the shared hosting population yet until everyone else catches up.  Most hosts (including <a href="http://inmotionhosting.com" target="_blank">IMH</a>) will still offer PHP 5.3 as an optional upgrade for customers on VPS or Dedicated servers, or as an optional move to a server that has that version. In the meantime, start upgrading your applications and keep tabs on your softwares&#8217; developers to find out when php 5.3 support will be available.  PHP 5.2 will likely become obscure near the end of 2010 or early 2011 in favor of 5.3, and you should be ready when it is.</p>
<p><map name='google_ad_map_334_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/334?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_334_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=334&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F27%2Fphp-5-3-why-were-all-late-to-the-party' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=334&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/05/27/php-5-3-why-were-all-late-to-the-party/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Command Line PHP: Part 3</title>
		<link>http://www.v-nessa.net/2010/05/25/command-line-php-part-3</link>
		<comments>http://www.v-nessa.net/2010/05/25/command-line-php-part-3#comments</comments>
		<pubDate>Tue, 25 May 2010 14:38:49 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=331</guid>
		<description><![CDATA[This is part third and final part in my PHP command line tutorial series. If you didn&#8217;t see parts 1 and 2: Command Line PHP: Part 1 Command Line PHP: Part 2 More File and Disk Functions Getting Disk Space and Usage The disk_total_size and disk_free_space functions can tell you how much disk space you [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F25%2Fcommand-line-php-part-3"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F25%2Fcommand-line-php-part-3&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>This is part third and final part in my PHP command line tutorial series. If you didn&#8217;t see parts 1 and 2:</p>
<p><a href="http://www.v-nessa.net/2010/05/18/command-line-php-part-1" target="_blank">Command Line PHP: Part 1</a></p>
<p><a href="http://www.v-nessa.net/2010/05/21/command-line-php-part-2" target="_blank">Command Line PHP: Part 2</a></p>
<p><span id="more-331"></span></p>
<h2>More File and Disk Functions</h2>
<h3>Getting Disk Space and Usage</h3>
<p>The <a href="http://us2.php.net/manual/en/function.disk-total-space.php" target="_blank">disk_total_size</a> and <a href="http://us2.php.net/manual/en/function.disk-free-space.php" target="_blank">disk_free_space</a> functions can tell you how much disk space you have and how much is available, respectively:</p>
<p><code>$disksize = disk_total_space("/");<br />
$size = round(number_format($disksize / 1024 / 1024 / 1024, 2));</code></p>
<p><code>$diskfree = disk_free_space("/");<br />
$freesize = round(number_format($diskfree / 1024 / 1024 / 1024, 2));</code></p>
<p><code>echo "Total Disk Size: $size GB\n";<br />
echo "Free Disk Space: $freesize GB";</code></p>
<h3>Finding Files</h3>
<p>A little-known function called glob works sort of like the locate command, in that it will find files that match a certain string, but it only looks in the current folder and is not recursive. For example, the below code will search for all files in the current folder that end with .txt:</p>
<p><code>foreach (glob("*.txt") as $file) {<br />
echo "$file size " . filesize($file) . "\n";<br />
}</code></p>
<p>You can also use something like <a href="http://snippets.dzone.com/posts/show/4147" target="_blank">this example</a> to run as a loop and recursively search through folders.</p>
<h3>Getting File Path Information</h3>
<p>The famous <a href="http://php.net/pathinfo" target="_blank">pathinfo</a> function can give you information about a file on your system:</p>
<p><code>$file = "/etc/php5/cli/php.ini";<br />
if(file_exists($file)){<br />
$info = pathinfo($file);<br />
print_r($info);<br />
}</code></p>
<p>This will print out an array like below:</p>
<p><code>Array<br />
(<br />
[dirname] =&gt; /etc/php5/cli<br />
[basename] =&gt; php.ini<br />
[extension] =&gt; ini<br />
[filename] =&gt; php<br />
)</code></p>
<p>Which you can echo out values to and use in your scripts, for example:</p>
<p><code>$file = "/etc/php5/cli/php.ini";<br />
if(file_exists($file)){<br />
$info = pathinfo($file);<br />
$dir = $info[dirname];<br />
chdir($dir);<br />
echo "Changed directory to" . getcwd();<br />
}</code></p>
<p>There are also similar functions that will provide the same information, individually:</p>
<p><code>$file = "/etc/php5/cli/php.ini";</code><br />
<code><br />
echo "Absolute File Name: " . <strong>realpath</strong>($file) . "\n";<br />
echo "File Name: " . <strong>basename</strong>($file) . "\n";<br />
echo "File path: " . <strong>dirname</strong>($file) . "\n";</code></p>
<p>This will return:</p>
<p><code>Absolute File Name: /etc/php5/cli/php.ini<br />
File Name: php.ini<br />
File path: /etc/php5/cli</code></p>
<h2>Some Random Script Fragments and Functions</h2>
<p><strong>Prompt a user for input:</strong></p>
<p><code><strong>fwrite</strong>(<strong>STDOUT</strong>, "Hello...\nWhat is your name? ");<br />
$name = trim(<strong>fgets</strong>(<strong>STDIN</strong>));<br />
fwrite(STDOUT, "Hello, $name!\n");</code></p>
<p><strong>Print out your username and date:</strong></p>
<p><code>$me = exec('whoami');<br />
echo "Hello, " . $me . " The time is currently " .date("r") . "\n";</code></p>
<p><strong>Generate random strings and passwords:</strong></p>
<p><code>echo <strong>crypt</strong>("mypassword","randomsalt");<br />
echo <strong>md5</strong>("mypassword");</code></p>
<p><strong>Random password, variable length:</strong></p>
<p><code>function randomPass($length) {</code></p>
<p><code>$chars = "abcdefghijkmnopqrstuvwxyz023456789";<br />
srand((double)microtime()*1000000);<br />
$i = 0;<br />
$pass = '' ;</code></p>
<p><code>while ($i &lt;= $length) {<br />
$num = rand() % 33;<br />
$tmp = substr($chars, $num, 1);<br />
$pass = $pass . $tmp;<br />
$i++;<br />
}</code></p>
<p><code>return $pass;<br />
}</code></p>
<p><code>$password = randomPass(10);</code></p>
<p><code>echo "Your random password is: $password";</code></p>
<p><strong>List loaded PHP extensions, check is specific extension is loaded:</strong></p>
<p><code>$extensions = <strong>get_loaded_extensions</strong>();<br />
foreach ($extensions as &amp;$value) {<br />
echo $value . "\n";<br />
}</code></p>
<p><code>if (!<strong>extension_loaded</strong>('gd')) {<br />
echo "GD extension is not loaded";<br />
exit;<br />
}</code></p>
<p><strong>Get Server&#8217;s CPU Load:</strong></p>
<p><code>$load = <strong>sys_getloadavg</strong>();<br />
echo "Current: " . $load[0] . "\n";<br />
echo "5-min: " . $load[1] . "\n";<br />
echo "15-min: " . $load[2] . "\n";</code></p>
<p><strong>Get PHP memory limit and convert to human-readable format:</strong><br />
<code><br />
function convert($size)<br />
{<br />
$unit=array('b','kb','mb','gb','tb','pb');<br />
return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];<br />
}<br />
echo convert(memory_get_usage(true));</code></p>
<h2>Some Useful Links/Tutorials</h2>
<p><a href="http://articles.sitepoint.com/article/php-command-line-1" target="_blank">Command Line PHP Tutorial</a><br />
<a title="Simple System Maintenance with PHP-CLI" href="http://www.developertutorials.com/tutorials/php/simple-system-maintenance-with-php-cli-8-01-17/" target="_blank">Simple System Maintenance with PHP-CLI &#8211; Simple System Maintenance with PHP-CLI</a><br />
<a href="http://www.ibm.com/developerworks/opensource/library/os-php-command/index.html" target="_blank">Command Line PHP (IBM)</a><br />
<a href="http://kevin.vanzonneveld.net/techblog/article/create_daemons_in_php/" target="_blank">Running Daemons in PHP</a><br />
<a href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/" target="_blank">PHP Class for Coloring Command Line Output</a><br />
<a href="http://brian.moonspot.net/php-progress-bar" target="_blank">PHP Command Line Progress Bar</a></p>
<p><map name='google_ad_map_331_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/331?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_331_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=331&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F25%2Fcommand-line-php-part-3' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=331&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/05/25/command-line-php-part-3/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Command Line PHP: Part 2</title>
		<link>http://www.v-nessa.net/2010/05/21/command-line-php-part-2</link>
		<comments>http://www.v-nessa.net/2010/05/21/command-line-php-part-2#comments</comments>
		<pubDate>Fri, 21 May 2010 19:51:25 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=315</guid>
		<description><![CDATA[This post is continuing on my three-part series on command line PHP programming. Missed part one? It&#8217;s right behind you. This part will go over command execution and processes. Command Execution Let&#8217;s start with the basics &#8211; you need to execute an arbitrary command from your PHP script. The exec, shell_exec, passthru, and system functions [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F21%2Fcommand-line-php-part-2"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F21%2Fcommand-line-php-part-2&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>This post is continuing on my three-part series on command line PHP programming. Missed part one? <a href="http://www.v-nessa.net/2010/05/18/command-line-php-part-1" target="_blank">It&#8217;s right behind you</a>. This part will go over command execution and processes.</p>
<p><span id="more-315"></span></p>
<h2>Command Execution</h2>
<p>Let&#8217;s start with the basics &#8211; you need to execute an arbitrary command from your PHP script. The <a href="http://php.net/exec" target="_blank">exec</a>, <a href="http://php.net/shell_exec" target="_blank">shell_exec</a>, <a href="http://php.net/passthru" target="_blank">passthru</a>, and <a href="http://php.net/system" target="_blank">system</a> functions will take care of this for you:</p>
<p><code>exec("/usr/bin/perl /scripts/myscript.pl");</code></p>
<p>will do about the same thing as:</p>
<p><code>system("/usr/bin/perl /scripts/myscript.pl");</code></p>
<p>and</p>
<p><code>shell_exec("/usr/bin/perl /scripts/myscript.pl");</code></p>
<p>So what&#8217;s the difference between the three? A little, but not much. The <a href="http://php.net/system" target="_blank">system</a> function will place the output of the command in an output stream, and display the results whether you tell it to or not. However, it&#8217;s mostly useful to return a yes or no output (in the form of 1, 0, or -1) based on the exit code of the command it was executing. For example, the below script views the /proc/cpuinfo file and outputs a boolean value on whether the command executed:</p>
<p><code>$cpuinfo = system("cat /proc/cpuinfo",$exitcode);<br />
echo $exitcode;<br />
</code><br />
I could then use the boolean value to write an if statement, which is more accurate because I&#8217;m basing the condition on the output of the command itself rather than PHP returning output based on the fact that the command ran, ignoring errors the command may have posted:</p>
<p><code>if($exitcode == 1){<br />
echo "Command executed, but finished with errors";<br />
}</code></p>
<p>The annoying part with the system function though is that it doesn&#8217;t suppress the output of the command itself, but rather sends it directly to the output stream. What if you want to format the output of the command? Then you would use <a href="http://php.net/exec" target="_blank">exec</a>. Below is an example of using the exec command to list the contents of a folder and only output .tar files (using <a href="http://us3.php.net/substr" target="_blank">substr</a> to split the string)</p>
<p><code>$dir = exec("ls .",$output);<br />
foreach ($output as $file)<br />
{<br />
if (strtolower(substr($file, -4)) == '.tar')<br />
echo "$file\n";<br />
}</code></p>
<p>The <a href="http://php.net/shell_exec" target="_blank">shell_exec</a> function allows you to emulate a shell environment. For example, in Linux you have a choice of shells like sh, bash, and ksh that, allow you to do things such as while loops. Using shell_exec is about the same as using the backtick operator, which is generally how you&#8217;re run commands within a Perl script:</p>
<p><code> $output = shell_exec('ls nonexistentfile  2&gt;&amp;1 1&gt; /dev/null');</code></p>
<p>// Does the same as</p>
<p><code>$output = `ls nonexistent file 2&gt;&amp;1 1&gt; /dev/null`l</code></p>
<p>Finally, there&#8217;s the <a href="http://php.net/passthru" target="_blank">passthru</a> function which, when invoked, immediately displays raw ouput of the command being executed. This is intended for browsers, to display binary data such as images, and not necessarily something you&#8217;re use on the command line:</p>
<p><code>header('Content-Type: image/jpg');<br />
passthru('cat /home/user/public_html/images/image.png');<br />
</code></p>
<h3>A Word on Security</h3>
<p>A lot of hosts block command execution functions with the disable_functions setting in php.ini or by using safe mode, and for good reason. A lot of malicious scripts contain code with executable functions, and especially when the value of command or argument is passed as a variable, the results can be destructive. Here&#8217;s an example of a simple script that lists files, that accepts a folder name as a argument:</p>
<p><code>$folder = $argv[1];<br />
exec("ls $folder");</code></p>
<p>We&#8217;d have a security problem if someone passed this as the first argument for $folder:</p>
<p><code>myfolder &amp;&amp; cat /etc/shadow</code></p>
<p>To prevent this, PHP has built-in functions to escape shell arguments and commands, in order to prevent things that could be dangerous:</p>
<p><a href="http://us3.php.net/manual/en/function.escapeshellarg.php" target="_blank">escapeshellarg</a>: Encloses command arguments in single quotes so the argument is passed as one string:</p>
<p><code>exec('ls '.escapeshellarg($folder));</code></p>
<p><a href="http://us3.php.net/manual/en/function.escapeshellcmd.php" target="_blank">escapeshellcmd</a>: Escapes characters that can be used to trick a shell command (like the &amp;&amp; I used to execute cat)</p>
<h2>Process Management &amp; POSIX</h2>
<p>PHP has internal  functions that allow you to manage processes, such as proc_open, proc_close, etc. However, I admit that these tend to be difficult to learn an understand, while posix functions tend to do the job with less hassle.  <a href="http://theserverpages.com/php/manual/en/ref.posix.php" target="_blank">Posix</a> functions are basically system-level functions. In the below script, I&#8217;m going to change the user that the script runs as, view simple information about the process, then start a counter to 1 million but kill it when it reaches 50:</p>
<p><code>$user = posix_getpwnam($vnessa5);<br />
<strong>posix_setuid</strong>($user['uid']);<br />
<strong>posix_setgid</strong>($user['gid']);<br />
$pid = getmypid();</code></p>
<p><code>print_r(<strong>posix_times</strong>());<br />
echo "Script owner: ". <strong>get_current_user</strong>() . "(" . <strong>getmyuid</strong>() . ")\n";<br />
$i=0;<br />
while( $i &lt; 10000000 ){<br />
$i++;<br />
if($i == 50){<br />
echo "Reached 50 - killing!";<br />
<strong>posix_kill</strong>($pid,1);<br />
}<br />
}</code></p>
<p>Similarly, <a href="http://php.net/posix_getpid" target="_blank">posix_getpid</a> and <a href="http://php.net/getmypid" target="_blank">getmypid</a> do the same thing. If the script is a child of another process, you can get the parent process&#8217;s ID with <a href="http://php.net/posix_getppid" target="_blank">posix_getppid</a>. The <a href="http://www.php.net/manual/en/function.getrusage.php" target="_blank">getrusage</a> function can also be used to get more informative information than <a href="http://php.net/posix_times" target="_blank">posix_times</a>. To kill a process, you can see I used <a href="http://php.net/posix_kill" target="_blank">posix_kill</a>, with the process ID and exit code as arguments. This is what happened when I ran the script:</p>
<p><code>Array<br />
(<br />
[ticks] =&gt; 1279790432<br />
[utime] =&gt; 0<br />
[stime] =&gt; 0<br />
[cutime] =&gt; 0<br />
[cstime] =&gt; 0<br />
)<br />
Script owner: root(0)<br />
Reached 50 - killing!Hangup</code></p>
<p>Keep in mind that in most situations, using die() to bail out of a script is more appropriate that using kill. I could rewrite that part of the code to say this instead:</p>
<p><code>die("Reached 50 - Bailing out!);</code></p>
<p>I also found a nice post on running background processes, that you might want to check out <a href="http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/" target="_blank">here</a>.</p>
<h2>Environmental Variables</h2>
<p>Environmental variables tend to be a major part of command line scripting, and is something that is part of PHP as well. Let&#8217;s start with defining an environmental variable with <a href="http://www.php.net/manual/en/function.putenv.php" target="_blank">putenv</a> and retrieving it with <a href="http://php.net/getenv" target="_blank">getenv</a>:</p>
<p><code>putenv("PATH=/fakebin");</code></p>
<p><code>if(!exec("test testdir")){<br />
echo "Could not execute test - path is " . getenv('PATH') ;<br />
}</code></p>
<p>In the above script, I set the $PATH environmental variable to /fakebin, so when I went to execute the &#8216;test&#8217; command (which is a valid Linux command located in /usr/bin/test), the scirpt could not find it since the command was not in /fakebin. This is about the same as setting the $PATH environment in a user&#8217;s .bashrc file. Keep in mind that the variable change lasts as long as the script does &#8211; after the script exits, the environmental variable is returned to its normal state. You can use getenv to pull any environmental variable, similar to the <a href="http://us.php.net/manual/en/reserved.variables.server.php" target="_blank">$_SERVER</a> superglobal.</p>
<p>A nice function for getting information about the current server is <a href="http://php.net/php_uname" target="_blank">php_uname</a>. You use it about the same way as the uname command in Linux:</p>
<p><code>echo php_uname();</code></p>
<p>Will return:</p>
<p><code>Linux server.v-nessa.net 2.6.18-028stab064.7 #1 SMP Wed Aug 26 13:11:07 MSD 2009 x86_64</code></p>
<p>You can further filter the output using the same arguments as uname, for instance, if I only need the server name:</p>
<p><code>echo php_uname(n);</code></p>
<p>PHP 5.3 also introduces a void function called <a href="http://php.net/gethostname" target="_blank">gethostname</a> which will get the hostname of your machine as well.</p>
<h3>The Server Superglobal</h3>
<p>The <a href="http://us.php.net/manual/en/reserved.variables.server.php" target="_blank">$_SERVER superglobal</a> is used to get environmental variables pursuant to the server and environment for the script you are running.  While it&#8217;s normally used in web applications, some of the values can be used for command line scripts as well:</p>
<p><code>echo "This file's name is " . $_SERVER['PHP_SELF'];</code></p>
<p>So you&#8217;ve made it part two of the series. Stay tuned for part three, which will go over specific system-level tasks and functions, with useful code snippets.</p>
<p>Next: <a href="http://www.v-nessa.net/2010/05/25/command-line-php-part-3" target="_blank">Command Line PHP: Part 3</a></p>
<p><map name='google_ad_map_315_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/315?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_315_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=315&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F21%2Fcommand-line-php-part-2' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=315&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/05/21/command-line-php-part-2/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Command Line PHP &#8211; Part 1</title>
		<link>http://www.v-nessa.net/2010/05/18/command-line-php-part-1</link>
		<comments>http://www.v-nessa.net/2010/05/18/command-line-php-part-1#comments</comments>
		<pubDate>Tue, 18 May 2010 18:10:26 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=310</guid>
		<description><![CDATA[PHP isn&#8217;t just for websites anymore. In fact, almost every script I&#8217;ve written to perform server-side functions is either written in bash or PHP, rather than Perl or Python as preferred by my colleagues. It&#8217;s a common belief that PHP isn&#8217;t suited for CLI programming since it&#8217;s mainly used in web applications, but PHP has [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F18%2Fcommand-line-php-part-1"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F18%2Fcommand-line-php-part-1&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>PHP isn&#8217;t just for websites anymore. In fact, almost every script I&#8217;ve written to perform server-side functions is either written in bash or PHP, rather than Perl or Python as preferred by my colleagues. It&#8217;s a common belief that PHP isn&#8217;t suited for CLI programming since it&#8217;s mainly used in web applications, but PHP has over a hundred functions specifically intended for system management.</p>
<p>These kinds of posts can be rather lengthy, so I&#8217;m making this into a series with three parts.  Part 1 will go over the basic filesystem functions. You can find a complete listing <a href="http://us.php.net/manual/en/ref.filesystem.php" target="_blank">here</a>, but I&#8217;ll just go over a few of the more important and common ones.</p>
<p><span id="more-310"></span></p>
<h2><strong>The hashbang</strong></h2>
<p>As with any CLI script, the first line of your PHP script should contain the executable binary for PHP. You can usually find this by running:</p>
<blockquote><p>which php</p></blockquote>
<p>On my server the location is /usr/bin/php, so here&#8217;s the first line of my script:</p>
<p><code>#!/usr/bin/php</code></p>
<p>If you installed PHP in a custom location, you&#8217;ll need to specify that binary instead. You can also specify <a href="http://www.php-cli.com/" target="_blank">command line options</a> like -f, -c, etc.  Then set the permissions of your script to 755 to allow it to execute.</p>
<h2><strong>Accepting arguments with PHP<br />
</strong></h2>
<p>A major part of CLI scripting is the ability to accept arguments. For this, we&#8217;ll write a simple script called asl.php which will parse my name, sex, and location as arguments:</p>
<blockquote><p>[nessa@server] ./test.php 23 female virginia</p></blockquote>
<p>Here&#8217;s the script:</p>
<p><code>#!/usr/bin/php<br />
&lt;?php</code></p>
<p><code>print_r($argv);</code></p>
<p><code>?&gt;</code></p>
<p>The $argv variable is native, and parses as an array. So running this script will produce the following output:</p>
<p><code>Array<br />
(<br />
[0] =&gt; ./asl.php<br />
[1] =&gt; 23<br />
[2] =&gt; female<br />
[3] =&gt; virginia<br />
)</code></p>
<p>So if I only wanted to echo out my age, I can use the following code:</p>
<p><code>echo $argv[1];</code></p>
<p>If you notice, there are four values instead of the three that I passed. As with most scripting languages, PHP considers the filename as the first (0) variable. To remove the first variable, use the <a href="http://us.php.net/array_shift" target="_blank">array_shift</a> function:</p>
<p><code>array_shift($argv);</code></p>
<p>This means now that using value #1 as shown in the example above will output &#8220;female&#8221; instead of 23, making the command line order more correct, but this tends to be confusing for some people since it makes the first value 0 instead of 1. I usually prefer NOT to shift the array unless having the file name in there is going to adversely affect the intended functionality of the script.</p>
<p>From here ( keeping in mind that I&#8217;m not shifting the array anymore), I can assign the arguments to variables and access them from the script:</p>
<p><code>$age = $argv[1];</code><br />
<code>$gender = $argv[2];</code><br />
<code>$location = $argv[3];</code><br />
<code>// echo out the values</code><br />
<code>echo "Hello, I am $age-year-old $gender from $location";</code></p>
<p>In some cases you may want to validate the number of arguments passed, or what they contain. For instance, the below example is requiring that all three variables are passed (however, the code says four, since you have to include the script name as the first &#8220;argument&#8221;, as mentioned before):</p>
<p><code>if ($argc != 4) {<br />
die("Usage: asl.php &lt;age&gt; &lt;gender&gt; &lt;location&gt;\n");<br />
}</code></p>
<p>You can of course specify <em>less than</em> (&lt;) or <em>greater than</em> (&gt;) values operators.  In the next example, I want to make sure that the &#8220;age&#8221; argument is a number:</p>
<p><code>if (!is_numeric($age)){<br />
die("$age is not a number");<br />
}</code></p>
<p>I&#8217;m sure by now you get the idea =)</p>
<h2><strong>PHP File and Folder Management</strong></h2>
<h3>Creating files and folders, and checking their accessibility</h3>
<p>Continuing my above example, I want to end up with a file in /opt/app/users called &#8220;users.txt&#8221; that contains a list of all the output of asl.php. I first need to see if  /opt/app/users exists using the <a href="http://us3.php.net/manual/en/function.is-dir.php" target="_blank">is_dir </a>function, and if it doesn&#8217;t, create it with <a href="http://us3.php.net/manual/en/function.mkdir.php" target="_blank">mkdir</a>, then enter into that directory with <a href="http://us.php.net/manual/en/function.chdir.php" target="_blank">chdir</a>:</p>
<p><code>$dirname = "/opt/app/users;<br />
if(!<strong>is_dir</strong>($dirname)){<br />
<strong>mkdir</strong>($dirname, 0755);<br />
}<br />
<strong>chdir</strong>($dirname);</code></p>
<p>What if /opt/app doesn&#8217;t exist and I need to create the entire structure? The mkdir function has a recursive flag that is set to false by default, but can be enabled as so:</p>
<p><code>$dirstructure = "/opt/app/users";</code></p>
<p><code>if (!mkdir($dirstructure, <strong>0</strong>, true)) {<br />
die('Failed to create folders!');<br />
}</code></p>
<p>Now that the folders are created and verified, I use <a href="http://www.php.net/manual/en/function.file-exists.php" target="_blank">file_exists</a> and <a href="http://www.php.net/manual/en/function.is-readable.php" target="_blank">is_readable</a> to make sure that my users.txt file is there and can be seen. If not, we&#8217;ll use one of the file functions to create it:</p>
<p><code>$cwd = <strong>getcwd</strong>();<br />
$filename = $cwd . "/users.txt;<br />
if(<strong>file_exists</strong>($filename) &amp;&amp; <strong>is_readable</strong>($filename)){<br />
echo "File Exists and is readable";<br />
}else{<br />
<em>echo "File does not exist or is not readable";</em></code><br />
<code>touch($filename);<br />
}</code></p>
<p>If you notice, I added the <a href="http://us.php.net/manual/en/function.getcwd.php" target="_blank">getcwd</a> function to look for a file called users.txt in my current directory. If you need to see whether a file is executable instead of readable, you can simply use the <a href="http://us.php.net/manual/en/function.is-executable.php" target="_blank">is_executable</a> function, or to see if it&#8217;s writable, use <a href="http://us.php.net/manual/en/function.is-writable.php" target="_blank">is_writable</a>:</p>
<p><code>$filename = '/opt/app/users/users.txt';</code></p>
<p><code>if (!is_executable($filename)) {<br />
echo $filename.' is not executable';<br />
}<br />
</code><code>if (!is_writable($filename)) {<br />
echo $filename.' is not writable';<br />
} </code></p>
<p>Note that the result of these commands is based on the user running them. For instance, if the file is owned by the user root and is set to 600 permissions (root read/write only), but the user &#8216;user1&#8242; is running the script, the tests in the above lines of code will fail since that user does not have permissions to the file in question.</p>
<h3>Creating and deleting files</h3>
<p>There are a few functions you can use to create files with PHP. Here are the most commonly used: <a href="http://us2.php.net/manual/en/function.fopen.php" target="_blank">fopen</a>, <a href="http://www.php.net/manual/en/function.file-put-contents.php" target="_blank">file_put_contents</a>, <a href="http://us2.php.net/manual/en/function.touch.php" target="_blank">touch,</a> If you want to delete a file, simply use <a href="http://us2.php.net/unlink" target="_blank">unlink</a>.  In the below example</p>
<p><code>$filename = "/opt/app/users/users.txt";<br />
unlink($filename);<br />
</code></p>
<p>Unlink is not to be confused with the opposite of <a href="http://us2.php.net/manual/en/function.symlink.php" target="_blank">symlink</a>, which creates a symbolic link  (shortbut) between files:</p>
<p><code>symlimk("/opt/app/users/users.txt", "/home/nessa/Desktop/users.txt-shortcut");</code></p>
<p>And <a href="http://php.net/rmdir" target="_blank">rmdir</a> will remove a folder:</p>
<p><code>if (!is_dir('temp')) {<br />
mkdir('temp');<br />
}<br />
rmdir('temp');</code></p>
<h3>Writing to files</h3>
<p>The most common way to write to files is using the fopen function. Using my original example, asl.php is going to write the values of the arguments to a file called users.txt:</p>
<p><code>$filename = "/opt/app/users/users.txt";<br />
$fh = fopen($filename, 'w') or die("can't open file");<br />
$data = $age . $gender . $location;<br />
fwrite($fh, $date);<br />
fclose($fh);</code></p>
<h3>Reading contents of a file</h3>
<p>If you want the script to read the file, you can use a number of function such as <a href="http://us3.php.net/manual/en/function.readfile.php" target="_blank">readfile</a>, <a href="http://us3.php.net/manual/en/function.file-get-contents.php" target="_blank">file_get_contents</a>, <a href="http://us3.php.net/manual/en/function.fopen.php" target="_blank">fopen</a>, <a href="http://us3.php.net/manual/en/function.fread.php" target="_blank">fread</a>, and <a href="http://us3.php.net/manual/en/function.file.php" target="_blank">file</a>. The actual function you would use depends on what you&#8217;re planning on doing with the data. If you simply want to display the contents of the file as a string:</p>
<p><code>$filename = "/opt/app/users/users.txt";<br />
$data = file_get_contents($filename);<br />
echo $data;</code></p>
<p>Will display:</p>
<p><code>23 female virginia</code></p>
<p>If you need a more programmatic way of displaying the data, such as reading each column as a set of values (like if you&#8217;re inserting all this into a database), you&#8217;d use the file() function which will load the contents of the file into an array. Here&#8217;s a simple loop that echoes out each line in the file:</p>
<p><code>$filename = "/opt/app/users/users.txt";<br />
$lines = file($filename);</code></p>
<p><code>foreach ($lines as $line_num =&gt; $line)</code><br />
<code>{<br />
print "{$line_num} : " . $line . "\n";<br />
}</code></p>
<h3>Reading contents of a folder</h3>
<p>You can use the <a href="http://us3.php.net/opendir" target="_blank">opendir</a> function to run a loop and read the contents of a folder:</p>
<p><code>// open the current directory by opendir</code></p>
<p><code>$dirname = "/opt/app";<br />
$handle=opendir($dirname);</code></p>
<p><code>while (($file = readdir($handle))!==false) {<br />
echo "$file \n";<br />
}</code></p>
<p><code>closedir($handle);</code></p>
<h3>Changing permissions and ownership:</h3>
<p>In the above example where I was checking to see if the file was readable, I didn&#8217;t actually specify anything to address permissions &#8211; instead, I just created the file. To change the permissions or ownership of files, you can use the <a href="http://us2.php.net/chmod" target="_blank">chmod</a> and <a href="http://us2.php.net/chown" target="_blank">chown</a> functions.</p>
<p><code>$filename = "/opt/appf/users/users.txt";<br />
$username = posix_getpwuid(fileowner($filename));</code></p>
<p><code>// Get the octal value of permissions<br />
$perms = substr(sprintf('%o', fileperms($filename')), -4);</code></p>
<p><code>if($username[name] != "nessa" &amp;&amp; $perms != "0755" ){<br />
chmod($filename, 0755);<br />
chown($filename, "nessa");<br />
echo "Permissions fixed";<br />
}else{<br />
echo "Permissions are correct";</code></p>
<p>If you want to change the umask (that is, the default permissions of files created by the script), you can use the <a href="http://us.php.net/manual/en/function.umask.php" target="_blank">umask</a> function &#8211; which actually revokes permissions instead of setting them.</p>
<h3>Copying, moving, and renaming</h3>
<p>Say I want to rename the /opt/app folder to /etc/app. I&#8217;d use the <a href="http://us.php.net/manual/en/function.rename.php" target="_blank">rename</a> function as so, validating on whether of not it was renamed successfully:</p>
<p><code>if(!rename("/opt/app","/etc/app")){<br />
echo "Rename failed";<br />
}</code></p>
<p>You can also use the <a href="http://us.php.net/manual/en/function.copy.php" target="_blank">copy</a> function to copy files, noting that if the &#8220;new&#8221; file or folder already exists, it will be overwritten.</p>
<p><code>if(!copy("/opt/app","/etc/app")){<br />
echo "Copy failed";<br />
}</code></p>
<h2>User and File information</h2>
<h3>Getting user and group data</h3>
<p>The <a href="http://us3.php.net/fileowner" target="_blank">fileowner</a> function as shown above will return the UID of the file, but I specified the username. You can use <a href="http://us3.php.net/manual/en/function.posix-getpwuid.php" target="_blank">posix_getpwuid</a> to return an array with the user&#8217;s information in a more usable format:</p>
<div>
<p><code>$filename = "/opt/app/users/users.txt";</code><code><br />
$username = posix_getpwuid(fileowner($filename));<code>print_r($username);</code></code></p>
</div>
<div>Will return:</div>
<p><code>Array<br />
(<br />
[name] =&gt; nessa<br />
[passwd] =&gt; x<br />
[uid] =&gt; 1000<br />
[gid] =&gt; 1000<br />
[gecos] =&gt; Vanessa V.,,,<br />
[dir] =&gt; /home/nessa<br />
[shell] =&gt; /bin/bash<br />
)</code></p>
<p>So you can simply echo out the array values of $username based on the keys. For example, to get the shell of the user in the above example, simply echo to the &#8216;shell&#8217; key from the $username array:</p>
<p><code>echo $username[shell];</code></p>
<p>If you want to get group information for a file, you can use the same method, but with <a href="http://us.php.net/manual/en/function.filegroup.php" target="_blank">filegroup</a> and <a href="http://us.php.net/manual/en/function.posix-getgrgid.php" target="_blank">posix_getgrgid</a>:</p>
<p><code>$filename = "/opt/app/users/users.txt";</code><br />
<code>print_r(posix_getgrgid(filegroup($filename)));</code></p>
<h3>Getting file information</h3>
<p>You can also get information about a file using the <a href="http://us.php.net/manual/en/function.stat.php" target="_blank">stat</a> or <a href="http://us.php.net/manual/en/function.fstat.php" target="_blank">fstat</a> functions, which return the results to an array:</p>
<p><code>$filename = "/opt/app/users/users.txt";</code><br />
<code>$stat = stat($filename);</code><br />
<code>print_r($stat);</code></p>
<p>Will return a giant array of information for the file. If you only want to return one value, say, the size, echo it out like you would a normal array:</p>
<p><code>echo $stat[size];</code></p>
<p>So here we&#8217;ve finished the first part of PHP command line scripting, which covered the use of files, folder, and users. The next parts will go over command execution and process management.</p>
<p>See: <a href="http://www.v-nessa.net/2010/05/21/command-line-php-part-2" target="_self">Command Line PHP: Part 2,</a> <a href="http://www.v-nessa.net/2010/05/25/command-line-php-part-3" target="_blank">Command Line PHP: Part 3<br />
</a></p>
<p><map name='google_ad_map_310_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/310?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_310_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=310&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2010%2F05%2F18%2Fcommand-line-php-part-1' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=310&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2010/05/18/command-line-php-part-1/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Simple API Writing, Part I</title>
		<link>http://www.v-nessa.net/2009/02/09/simple-api-writing-part-i</link>
		<comments>http://www.v-nessa.net/2009/02/09/simple-api-writing-part-i#comments</comments>
		<pubDate>Tue, 10 Feb 2009 02:55:05 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[cpanel]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=189</guid>
		<description><![CDATA[A lot of people don&#8217;t realize how easy it is to write an API with PHP. It really is as easy as having a simple PHP script accepting GET variables, and when you add in some security, you can pretty much do anything you want with a single script that accepts variables from any authenticated [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2009%2F02%2F09%2Fsimple-api-writing-part-i"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2009%2F02%2F09%2Fsimple-api-writing-part-i&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>A lot of people don&#8217;t realize how easy it is to write an API with PHP. It really is as easy as having a simple PHP script accepting GET variables, and when you add in some security, you can pretty much do anything you want with a single script that accepts variables from any authenticated source.  So a little while ago I <a href="http://www.v-nessa.net/2008/05/07/sexifying-whm-with-xml-api" target="_blank">posted about the new cPanel XML API</a> and how to integrate that with your own scripts &#8211; well now, I&#8217;ll use that as an example to show you how to write an API for <em>their</em> API, a.k.a, an API connector.   Though in real applications you wouldn&#8217;t need an API, all you&#8217;d need is a PHP script that accepts GET or POST input to perform some kind of action. In this example, we&#8217;ll have a script that automatically adds DNS zones to a nameserver that runs cPanel as well.</p>
<p>Most APIs do the same thing &#8211; you have a script, then that script accepts post/get variables, then does something.</p>
<p>The Interface (addzone.php):</p>
<p>You guy remember the one I posted a while back &#8211; well, we&#8217;ll use the same one only a tad different.  This is the script that runs statically on the server, which accepts the variables passed through the URL:</p>
<p><code><br />
<span style="color: #ff66cc;"></span></code><span style="color: #ff66cc;">&lt;?php<br />
// API for adding a DNS zone to ns cluster<br />
$isinclude = &#8220;1&#8243;; // specifies $isinclude for xmlapi.php<br />
// GET &amp; POST definitions</span></p>
<p><span style="color: #ff66cc;">$key = &#8220;098f6bcd4621d373cade4e832627b4f6&#8243;;<br />
$domain = $_GET['domain'];<br />
$ip = $_GET['ip'];</span></p>
<p><span style="color: #ff66cc;">// Validation &#8211; make sure that we have the right information</span></p>
<p><span style="color: #ff66cc;">if($_POST['key'] != $key){ echo &#8220;Invalid key!!&#8221;; die(); }<br />
if(empty($domain)){ echo &#8220;Domain value missing!!&#8221;; die(); }<br />
if(empty($ip)){ echo &#8220;IP Value missing!!&#8221;; die(); }</span></p>
<p><span style="color: #ff66cc;">$theServer = &#8220;ns1.v-nessa.net&#8221;; // the server to connect to<br />
$apiPath = &#8220;/xml-api/adddns?domain=$domain&amp;ip=$ip&#8221;; // the xml api path<br />
</span></p>
<p><span style="color: #ff66cc;">$user = &#8220;root&#8221;; // use to connect to whm as<br />
</span></p>
<p><span style="color: #ff66cc;">// ns1 hash (whm &gt; remote access)<br />
</span></p>
<p><span style="color: #ff66cc;">$rhash = &#8220;</span><span style="color: #ff66cc;">e9917f16b3fda69137192725a06b68e7</span><br />
<span style="color: #ff66cc;"> 230e99fd445473807e33d637878641a5<br />
&#8211;edited out for sake of length&#8211;<br />
f673567ab443acedc77f9aec62ff953f&#8221;;</span></p>
<p><span style="color: #ff66cc;">// Include the API connector<br />
include(&#8220;xmlapi.php&#8221;);</span></p>
<p><span style="color: #ff66cc;">// Output XML Result<br />
$xmlObject=simplexml_load_string($xmlresult);</span></p>
<p><span style="color: #ff66cc;">echo $xmlObject-&gt;result-&gt;statusmsg . &#8220;\n&#8221;;</span></p>
<p><span style="color: #ff66cc;">?&gt;</span></p>
<p>The file that is called via include() is the basic xml function file which constructs all of the variables from the outser script (shown above).  You can get a copy of of xmlapi.php from <a href="http://v-nessa.net/scripts/whmapi/xmlapi" target="_blank">here</a>, but for this example you need to comment out the output.</p>
<p>Now all we need to do is pass the variables that the script needs in order to know what information to process, which is $ip and $domain.  Therefore, in order to successfully call this API, you would enter the following in a browser:</p>
<blockquote><p>http://v-nessa.net/api/addzone.php?domain=test.v-nessa.net&amp;ip=205.134.252.71</p></blockquote>
<p>This will pass the &#8216;domain&#8217; and &#8216;ip&#8217; variables to addzone.php, which uses the XML API to connect to WHM and add a dns zone on the nameserver ns1.v-nessa.net.  This is a problem though &#8211; what&#8217;s to keep outsiders from finding this and abusing it?  Well, there are several forms of non-interactive authentication you can use, such as:</p>
<ul>
<li>Have an allow list of ips that can access the script (look up environmental variables at php.net)</li>
<li>Requiring a key or token</li>
</ul>
<p>I generally use a key, though there are better ways to do this.  The way I&#8217;m about to show you is simple and secure, but slightly limits the way your API can be called.</p>
<p>First, I generated an md5 hash and defined it in the scipt (remember <span style="color: #ff66cc;">$key = &#8220;098f6bcd4621d373cade4e832627b4f6&#8243;; <span style="color: #000000;">?).  Then all I need to do is make sure that key is used whenever I call the API. Notice that in addzone.php it&#8217;s defined as a POST variable?  That is mainly for preference but you can just as easily make it a GET variable and just add it to your URL line.  Here I want it to be posted, so I can call the API through cURL as follows:</span></span></p>
<blockquote><p>curl -k http://v-nessa.net/api/addzone.php?domain=test.v-nessa.net&amp;ip=205.134.252.71 -d <span style="color: #ff66cc;">key = &#8220;098f6bcd4621d373cade4e832627b4f6</span></p></blockquote>
<p><span style="color: #ff66cc;"><span style="color: #000000;">And there you have it! A very simple way to write an API using POST and GET.</span><br />
</span></p>
<p><span style="color: #ff66cc;"><br />
</span></p>
<p><!--adsense--></p>
<p><map name='google_ad_map_189_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/189?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_189_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=189&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2009%2F02%2F09%2Fsimple-api-writing-part-i' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=189&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2009/02/09/simple-api-writing-part-i/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Alternative PHP Caching FTW</title>
		<link>http://www.v-nessa.net/2008/06/27/alternative-php-caching-ftw</link>
		<comments>http://www.v-nessa.net/2008/06/27/alternative-php-caching-ftw#comments</comments>
		<pubDate>Fri, 27 Jun 2008 12:24:47 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/2008/03/27/alternative-php-caching-ftw</guid>
		<description><![CDATA[.!. We get a TON of requests for the PHP APC pecl module because after having adopted suPHP into our configuration, eAccelerator is worthless. It&#8217;s quick to install, and especially if you&#8217;re running suPHP or phpsuexec, each user can maintain their own settings within their local php.ini without me having to do anything &#8212; basically [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F27%2Falternative-php-caching-ftw"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F27%2Falternative-php-caching-ftw&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<div style="display:none">.!.</div>
<p>We get a TON of requests for the <a href="http://us3.php.net/apc" target="_blank">PHP APC</a> pecl module because after having adopted suPHP into our configuration, eAccelerator is worthless.  It&#8217;s quick to install, and especially if you&#8217;re running suPHP or phpsuexec, each user can maintain their own settings within their local php.ini without me having to do anything &#8212; basically the best thing that a lazy system admin can ask for.</p>
<p>Soooo, here&#8217;s how you install it:</p>
<p><code><br />
<span style="color: #ff66cc;"> wget http://pecl.php.net/get/APC-3.0.17.tgz<br />
tar -xvzf  APC-3.0.17.tgz<br /> <strong style="display:none"></strong><br />
phpize<br />
./configure &amp;&amp; make &amp;&amp; make install</span><br />
</code></p>
<p>Then just add &#8220;extension=/apc.so&#8221; to your php.ini and you&#8217;re done.  With PHP under Apache this will load the APC module for everyone, but for suPHP users you&#8217;ll need to add it to their php.ini which will also allow them to <a href="http://us3.php.net/apc" target="_blank">modify their own APC settings</a>. These are the ones I recommend using:</p>
<pre><span style="color: #ff66cc;">apc.enabled = 1</span></pre>
<pre><span style="color: #ff66cc;">apc.shm_segments = 1</span></pre>
<pre><span style="color: #ff66cc;">apc.shm_size = 30</span></pre>
<pre><span style="color: #ff66cc;">apc.optimization = 0</span></pre>
<pre><span style="color: #ff66cc;">apc.ttl = 7200</span></pre>
<pre><span style="color: #ff66cc;">apc.user_ttl = 7200</span></pre>
<pre><span style="color: #ff66cc;">apc.num_files_hint = 1000</span></pre>
<pre><span style="color: #ff66cc;">apc.mmap_file_mask = /tmp/apc.XXXXXX</span></pre>
<p>Now, if you want to get even sexier with it I came across <a href="http://www0.fh-trier.de/~beckerr/apcphpgui.phtml" target="_blank">this little tool</a> that monitors the performance of APC on your server.</p>
<p><!--adsense--></p>
<p><map name='google_ad_map_149_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/149?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_149_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=149&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F27%2Falternative-php-caching-ftw' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=149&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2008/06/27/alternative-php-caching-ftw/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Sexifying WHM with XML API</title>
		<link>http://www.v-nessa.net/2008/06/07/sexifying-whm-with-xml-api</link>
		<comments>http://www.v-nessa.net/2008/06/07/sexifying-whm-with-xml-api#comments</comments>
		<pubDate>Sat, 07 Jun 2008 09:33:30 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[cpanel]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=155</guid>
		<description><![CDATA[.!. I don&#8217;t know about you other cPanel system admins out there, but I find WHM to be very useful for the more advanced and time-consuming tasks, such as installing SSL certificates. However, the easy stuff like changing an account&#8217;s package and resetting passwords is a royal pain in the ass as far as convenience [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F07%2Fsexifying-whm-with-xml-api"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F07%2Fsexifying-whm-with-xml-api&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<div style="display:none">.!.</div>
<p>I don&#8217;t know about you other cPanel system admins out there, but I find WHM to be very useful for the more advanced and time-consuming tasks, such as installing SSL certificates.  However, the easy stuff like changing an account&#8217;s package and resetting passwords is a royal pain in the ass as far as convenience is concerned when you have to log into WHM, list accounts, and make whatever change.</p>
<p>I recently became favorable towards the WHM XML API functionality which will let me do a majority of the everyday account-related tasks from command line without ever opening my browser, which is a lot easier when managing thousands of users across multiple servers.  Below are a couple scripts I&#8217;ve put together using the XML API from a base script in the cPanel forums:</p>
<p><a href="http://v-nessa.net/scripts/whmapi/chacctpass" target="_blank">Change account password</a></p>
<p><a href="http://v-nessa.net/scripts/whmapi/chpkg" target="_blank">Change account package</a></p>
<p>Both are run via command line, and the arguments passed to the PHP script as variables.  For example, to change an account&#8217;s password:</p>
<blockquote><p>./chacctpass myuser mypass1234</p>
</blockquote>
<p>Customizing these scripts to perform different functions is easy via the following steps:</p>
<p>- change<strong> if ($argc != 3)</strong> to the number of command line arguments you wish to pass to the script plus one.  In the above example there are two arguments and since the script name counts, add one and that makes 3.</p>
<p>- in the section where the arguments are assigned to variables (like $cpuser, etc), name your variables.  The first one should have an array value of 0, then 1, 2, etc.</p>
<p>- edit the usage example, which will come up if the required number of arguments is not provided&#8230;you can add any text you like</p>
<p>- if you&#8217;re using a hash (which is more secure than user/pass authentication), go fetch your remote access key from WHM and put it in the <strong>$hash</strong> value within quotes, format intact.  Otherwise, put in your WHM user&#8217;s username and password</p>
<p>- change the <strong>$server</strong> variable to your server&#8217;s hostname</p>
<p>- change <strong>$apipath</strong> to the WHM path for the function you are using.  You can find a whole list of them <a title="WHM API Functions" href="http://www.cpanel.net/plugins/xmlapi/" target="_self">here</a>, and most will give you the path to use in the examples sections.   In the API path, insert your variable names where the values are suppose to be.  For instance:</p>
<blockquote><p>$apiPath = &#8220;/xml-api/passwd?user=myuser&amp;pass=mypass1234&#8243;;</p>
</blockquote>
<p>Would be:</p>
<blockquote><p>$apiPath = &#8220;/xml-api/passwd?user=$cpuser&amp;pass=$newpass&#8221;;</p>
</blockquote>
<p>In the header section, uncomment whichever <strong>$header .= &#8220;Authorization:</strong> line that matches your authentication method (user/pass or hash)</p>
<p>Once you&#8217;ve configured your API script, chmod to 700 and run from the command line as show in my example.  It&#8217;s better to lock down the script by changing its ownership only to the user that will be using it, and not giving read, write, or execute permissions to anyone else.</p>
<p><strong>Note:</strong> for these scripts to work you have to have PHP compiled with OpenSSL support, otherwise change the socket variables to http over port 2086.</p>
<p><!--adsense#half--></p>
<p><map name='google_ad_map_155_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/155?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_155_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=155&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2008%2F06%2F07%2Fsexifying-whm-with-xml-api' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=155&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2008/06/07/sexifying-whm-with-xml-api/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Moving Towards PCI Compliance with cPanel</title>
		<link>http://www.v-nessa.net/2008/04/14/moving-towards-pci-compliance-with-cpanel</link>
		<comments>http://www.v-nessa.net/2008/04/14/moving-towards-pci-compliance-with-cpanel#comments</comments>
		<pubDate>Mon, 14 Apr 2008 09:31:50 +0000</pubDate>
		<dc:creator>Nessa</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[cpanel]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://www.v-nessa.net/?p=151</guid>
		<description><![CDATA[Those of you who are server admins or use certain merchant services know what I&#8217;m taking about &#8212; it&#8217;s that dreaded security scan that picks apart your server to tell you everything that it thinks is wrong, assuming you have the knowledge or access to fix it: yes, the PCI scan. PCI compliancy is a [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F04%2F14%2Fmoving-towards-pci-compliance-with-cpanel"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.v-nessa.net%2F2008%2F04%2F14%2Fmoving-towards-pci-compliance-with-cpanel&amp;source=nessa421&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p><img class="alignleft" style="float: left; margin: 5px;" src="http://v-nessa.net/images/yousuck.gif" alt="" width="198" height="265" />Those of you who are server admins or use certain merchant services know what I&#8217;m taking about &#8212; it&#8217;s that dreaded security scan that picks apart your server to tell you everything that it thinks is wrong, assuming you have the knowledge or access to fix it:  yes, the PCI scan.  PCI compliancy is a somewhat new procedure used by security companies and financial institutions to measure the security of a webserver that collects and stores sensitive information.  The reasons for getting a scan vary,  but are most commonly for legal reasons or just the assurance that your server is subject to certain vulnerabilities.</p>
<p>After dealing with 2-3 PCI scans a week for the last year, I&#8217;ve put together a common procedure for how to make your server compliant to current PCI standards.  Note that each scan company is different and may report other issues, and if you&#8217;re using ControlScan then, well, I feel sorry for you.  I&#8217;m also assuming that you are on a Linux server running cPanel and LAMP.</p>
<p><strong>Step 1: Make sure you have a firewall</strong></p>
<p>PCI scans are nazis about unjustified open ports, so only open the ones that you need in order for services to run effectively.  Manually configuring iptables is a pain in the ass, so I recommend using <a title="How to Install APF" href="http://missysadmin.com/2007/07/30/installing-apf-advanced-policy-firewall/" target="_blank">APF</a> or <a title="ConfigServer Firewall" href="http://www.configserver.com/cp/csf.html" target="_blank">CSF</a> (if you have cPanel) and then configuring the allow rules to only allow ports for active services.</p>
<p>Note that both indicate the opening of cPanel ports 2082, 2095, and 2086, but some scans will complain about these being nonsecure.  If that is the case you can configure within WHM to only use the secure ports, then remove the nonsecure ones from the firewall so they can&#8217;t be accessed.  You should also close MySQL port 3306 for external hosts and allow them on a per-IP basis to anyone other than localhost has to be allowed.</p>
<p><strong>Step 2: Update your system</strong></p>
<p>This is an obvious one, but you&#8217;d be surprised how many people still have old packages installed on the server.  With cPanel, running <strong>/scripts/upcp</strong> will usually update the vital system software as long as you have your update configuration in WHM set to allow it, but otherwise I would recommend doing a <strong>yum update</strong>, <strong>up2date</strong>, or whatever else you use to manage packages to make sure everything is up to date.</p>
<p>Nowadays old versions of MySQL, PHP, and Apache are no longer squeezing through either, so you need to upgrade to at least MySQL 4.1.22, PHP 5.2.5, and Apache 1.3.39 (some scans will want Apache 2.0.x).</p>
<p><strong>Step 3: FIx OpenSSL</strong></p>
<p>If you did a package update this was probably already taken care of, but if you installed via source you need to make sure you&#8217;re using at least 0.9.7j, which is the oldest version that most PCI scans allow.  You can get your sources from <a title="OpenSSL " href="http://www.openssl.org/source/" target="_blank">here</a>, and it may require a recompile of Apache and other services that use it.  To check your OpenSSL version, type &#8216;<strong>openssl</strong>&#8216; from your SSH prompt and then type &#8216;<strong>version</strong>&#8216;.</p>
<p><em>Note to Redhat/Fedora/CentOS users:</em> If you&#8217;re running a somewhat recent version of your OS your openSSL version probably is something like 0.9.7a, but due to <a title="About RedHat backporting" href="http://www.redhat.com/security/updates/backporting/" target="_blank">Redhat backporting</a> this may be a false-positive.  If you&#8217;re on any Redhat-based distribution, just tell your scan company and they&#8217;ll bypass OpenSSL checks.</p>
<p><strong>Step 4: Check your SSL certificates</strong></p>
<p>In order to pass a PCI scan your server must have at least one SSL certificate signed by a recognized certificate authority, and any services using SSL need to be using a certificate as well.  Go cough up $30-$100 and buy a decent 264-bit SSL certificate and install it not just for Apache, but also for all of your active services.  WebHost Manager has a section for installing service SSL certificates to make this process easier.</p>
<p><!--adsense--></p>
<p><strong>Step 5:  Disable SSLv2 and other weak encryption methods</strong></p>
<p>This one always gets me, because there is no way to disable SSLv2 for everything at once, at least not one that I know of.  What makes this part the worse is that not all services support the choosing of SSL protocols and ciphers, but luckily unless you are using ControlScan the ones that don&#8217;t are probably not going to show up.  Here&#8217;s how you do it for common services that are reported:</p>
<p><span style="color: #008000;">Apache:</span></p>
<p>Add these lines to your httpd.conf (you may to add them to each secure vhost as well):</p>
<pre><span style="color: #ff66cc;">SSLProtocol -ALL +SSLv3 +TLSv1
SSLCipherSuite ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM
</span></pre>
<p><span style="color: #008000;">POP3 and IMAP:</span></p>
<p>Edit the following files:</p>
<p>/usr/lib/courier-imap/etc/pop3d-ssl<br />
/usr/lib/courier-imap/etc/imapd-ssl</p>
<p>Comment out the existing <strong>TLS_CIPHER_LIST</strong> line and replace it with the following and restart courier-imap:</p>
<pre><span style="color: #ff66cc;">TLS_CIPHER_LIST="ALL:!SSLv2:!ADH:!NULL:!EXPORT:!DES:!LOW:@STRENGTH"</span></pre>
<p><span style="color: #008000;">Exim:</span></p>
<p>Add the following to exim.conf:</p>
<pre><span style="color: #ff66cc;">tls_require_ciphers = ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM:!SSLv2</span></pre>
<p>For other services that might be on your system, take a look at <a href="http://adamyoung.net/Disable-SSLv2-System-Wide" target="_blank">this guide</a>.</p>
<p><strong>Step 6: Disable mod_userdir (or whatever cPanel is calling it nowadays)</strong></p>
<p>If you are able to go to http://yourserverip/~yourusername, then you have mod_userdir enabled and the scan will probably complain.  You can disable this in WHM under Security Center &gt; Apache mod_userdir Tweak, or in httpd.conf add &#8220;userdir disabled user1 user2 user3 &#8230;etc&#8221;</p>
<p><strong>Step 7: Put Apache in incognito mode and disable the bad stuff<br />
</strong></p>
<p>If you try to get an Apache error (like a 404 error), the footer of that page probably contains more information that you may want to share about your Apache setup.  You can disable this in your httpd.conf by adding these lines:</p>
<pre><span style="color: #ff66cc;">ServerSignature Off
ServerTokens Prod
</span><span style="color: #ff66cc;">FileETag None</span></pre>
<p>You can read more about these <a href="http://www.petefreitag.com/item/419.cfm" target="_blank">here</a>.</p>
<p>Another thing that some scans report is the use of 413 errors.  You should add this line to httpd.conf as a workaround:</p>
<pre><span style="color: #ff66cc;">ErrorDocument 413 /index.php</span> (or any other file)</pre>
<p>Just about all scans will complain if the &#8216;trace&#8217; and &#8216;track&#8217; apache methods are enabled on your server.  You can fix this by adding these lines to your Virtualhost entries or .htaccess files:</p>
<pre><span style="color: #ff66cc;">RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)$ [NC]
RewriteRule ^.*$ - [F]</span></pre>
<p>You should also disable directory indexes, which can be done most easily in your cPanel&#8217;s index manager.  Directory indexes allow the listing of files inside folders that do not have an index page.  You can also disable these in your .htaccess files:</p>
<p><span style="color: #ff66cc;"> <code>Options All -Indexes</code></span></p>
<p><strong>Ending notes</strong></p>
<p>Really, it doesn&#8217;t matter how secure your server is if your web application scan is poorly programmed, so your server should not be the ending point in security.  Some PCI scan companies are able to detect common vulnerabilities in web applications, but you should take the extra steps to stay ahead of the game and update your site software on a regular basis.</p>
<p><!--adsense#img_banner--></p>
<p><map name='google_ad_map_151_7fa65e237551a74a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/151?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_151_7fa65e237551a74a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=151&amp;url= http%3A%2F%2Fwww.v-nessa.net%2F2008%2F04%2F14%2Fmoving-towards-pci-compliance-with-cpanel' /></p><img src="http://www.v-nessa.net/?ak_action=api_record_view&id=151&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.v-nessa.net/2008/04/14/moving-towards-pci-compliance-with-cpanel/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>
