#!/usr/bin/php5 -qC
<?
/*
 * APAMOD 0.4
 * Tool for modifying VirtualHost in Apache-Config
 * (C) 2002-2010 by Folke Ashberg <folke@ashberg.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * Usage: apamod <DOMAIN> <ACTION> [<PARAM> <PARAM2> ...]
 * 
 * Actions:
 *     getservername    Print the ServerName
 *     getserveraliases Print Aliases
 *     getnames         Print ServerName and Aliases
 *     setnames         Set new ServerName and Aliases
 *     getsection       Write VH-Section into file <PARAM> [lock with <PARAM2>]
 *     setsection       Write VH-Section from file <PARAM> [unlock using <PARAM2>]
 *     getline          Get line(s) starting with <PARAM>
 *     ___line          Modify the line(s) starting with <PARAM>
 *         setline      Change the line(s) to <PARAM2>, add if not exists
 *                       Name is changed to <PARAM3> if given
 *         modline      Modify the line(s) to <PARAM2>, only if found
 *                       Name is changed to <PARAM3> if given
 *         addline      Add a line named <PARAM> [<PARAM2>]
 *         delline      Delete the line(s)
 *         remline      Remark the line(s)
 *    unlock            Unlock vh-file [using <PARAM>]
 *   Special Domains: (no operations possible)
 *     getallnames      Get ALL ServerNames
 *     getallvhosts     Get ALL ServerNames and ServerAliases
 *
 */

$httpd_conf="/etc/apache2/apache2.conf";

$debug=0;

$dom=$_SERVER['argv'][1];
$action=$_SERVER['argv'][2];
$param=$_SERVER['argv'][3];
$param2=$_SERVER['argv'][4];
$param3=$_SERVER['argv'][5];
if (!
$dom){
    
usage();
    exit(
1);
}

$domrx=rx_quote($dom);
#print "DOMRX: $domrx\n";

function rx_quote($in){
    
$out=str_replace(".""\."$in);
    
$out=str_replace("*""\*"$out);
    
$out=str_replace("(""\("$out);
    
$out=str_replace("[""\["$out);
    
$out=str_replace("{""\{"$out);
    
$out=str_replace(")""\)"$out);
    
$out=str_replace("]""\]"$out);
    
$out=str_replace("}""\}"$out);
    
$out=str_replace("|""\|"$out);
    
$out=str_replace("+""\+"$out);
    
$out=str_replace("?""\?"$out);
    
$out=str_replace("/""\/"$out);
    return 
$out;
}


function 
fatal($msg){
    
$stderr=fopen("php://stderr""w");
    
fputs($stderr,$msg."\n");
    
fclose($stderr);
    exit(
1);
}

$invhost=false;
$found=0;
function 
scanfile($file){
    global 
$debug$action$dom$domrx$vhost_start$vhost_end$vhost_file$vhost_name$vhost_alias ;
    global 
$invhost$found$action;
    global 
$oldfile$oldlinenr;
    if (!
file_exists($file)){
    
$cnt=0;
    
exec("sh -c 'ls $file' 2>/dev/null", &$out, &$ret);
    
$ret=false;
    if (!
$ret){
        for (
$a=0$a<count($out); $a++){
        if (
$debug) print "Include->Expanded ".$out[$a]." at $oldfile:$oldlinenr\n";
        if (
scanfile($out[$a])) $ret=true;
        if (
$ret) return $true;
        }
    }
    
//fatal("$file does not exists");
    
return false;
    }
    
$f=file($file);

    
reset($f);
    
$linenr=0;
    while (list(
$n,$v)=each($f)){
    
$linenr=$n+1;
    if (
$invhost && ($dom=="getallnames" || $dom=="getallvhosts")) printservernames($v$dom);
    if (
preg_match("/^[[:space:]]*<virtualhost/i"$v)){
        if (
$invhost){
        
fatal("VHost in Vhost!");
        }
        if (
$debug) print "VHost-Section Start\n";
        
$vhost_start=$n;
        
$vhost_file=$file;
        
$invhost=true;
        
// go some lines back
        
$back=0;
        
$pos=$n-1;
        while (
$pos>=&& $back<2){
        if (!
trim($f[$pos])){
            
// empty line
            
if ($back==1){
            
// ..afer # block, so exit
            
$pos++;
            break;
            }
        } else if (
preg_match("/^[[:space:]]*#/"$f[$pos])){
            if (
$back==0$back=1;
        } else {
            
$pos++;
            break;
        }
        
$pos--;
        }
        
$vhost_start=$pos;
    } else if (
preg_match(
            
"/^[[:space:]]*servername"
            
."[[:space:]]+".$domrx."([[:space:]]+|$)/i"$v)){
        if (
$debug) print "VHost found! (ServerName at Line $file:$linenr)\n";
        if (
$invhost){
        
$found=1;
        }
    } else if (
preg_match(
            
"/^[[:space:]]*serveralias"
                
."[[:space:]]*.*[[:space:]]+".$domrx."([[:space:]]+|$)[^#]*/i"$v)){
        if (
$debug) print "VHost found! (ServerAlias at Line $file:$linenr)\n";
        if (
$invhost){
        
$found=2;
        }

    } else if (
preg_match("/^[[:space:]]*<\\/virtualhost/i"$v)){
        if (
$debug) print "VHost-Section Ends (found: $found)\n";
        
$invhost=false;
        if (
$found){
        if (
$debug) print "Found is set, will return true\n";
        
$vhost_end=$n;
        return 
true;
        }
    } else if (
preg_match("/^[[:space:]]*Include[[:space:]]+([^[:space:]]*)/i"$v$ergs)){
        if (
$invhost){
        if (
$debug) print "We don't handle Include in VHost-Section\n";
        continue;
        }
        
$newfile=trim($ergs[1]);
        if (
$debug) print "Include $newfile at $file:$linenr\n";
        
$oldfile=$file;
        
$oldlinenr=$linenr;
        if (
scanfile($newfile)) return true;
    }
    }
    if (
$debug) print "End of scanfile (found: $found)\n";
    if (
$found) return true;
    return 
false// not found 
}

function 
unlock($lockfile){
    
unlink($lockfile);
}

function 
checklock($lockfile$value){
    if (
file_exists($lockfile)){
    
//locked by us?
    
$content=file($lockfile);
    if (
trim($content[0])==trim($value)) return true;
    return 
false;
    }
    return 
true;
}


function 
writelock($lockfile$value){
    if (!
checklock($lockfile$value)) return false;
    if (!(
$fp=@fopen($lockfile"w+"))) fatal("Cant write lockfile '$lockfile'");
    
fputs($fp$value);
    
fclose($fp);
    return 
true;
}



function 
scan_servernames(){
    global 
$servername$serveralias;
    global 
$vhost_start$vhost_end$vhost_file;
    if (!
file_exists($vhost_file)) fatal("$vhost_file does not exists");
    
$servername="";
    
$serveralias=Array();
    
$f=file($vhost_file);
    
reset($f);
    for (
$a=$vhost_start;$a<=$vhost_end;$a++){
    
$v=$f[$a];
    if (
preg_match(
            
"/^[[:space:]]*servername"
            
."[[:space:]]+([^#]*)([[:space:]]+|$)/i"$v$erg)){
        
$servername=trim($erg[1]);
    } else if (
preg_match(
            
"/^[[:space:]]*serveralias"
            
."[[:space:]]*([^#]+)/i"$v$erg)){
        
$found=2;
        
$names=split("[ \t]"$erg[1]);
        
reset($names);
        while (list(
$n,$vv)=each($names)) $serveralias[]=trim($vv);
    }
    }
// scan_servernames

function printservernames($line$what){
    
#    print "LINE: $line\n";
    
if (preg_match(
            
"/^[[:space:]]*servername"
            
."[[:space:]]+([^#]*)([[:space:]]+|$)/i"$line$erg)){
    print 
trim($erg[1]). " ";
    } else if (
$what=="getallvhosts" && preg_match(
            
"/^[[:space:]]*serveralias"
            
."[[:space:]]*([^#]+)/i"$line$erg)){
    
$names=split("[ \t]"$erg[1]);
    
reset($names);
    while (list(
$n,$vv)=each($names)) print trim($vv)." ";
    }
}


$erg=scanfile($httpd_conf);
if (
$dom=="getallnames" || $dom=="getallvhosts"){
    exit;
}

if (!
$erg){
    
fatal("Not found!");
}

$lockfile=$vhost_file.".lock";

if (
$action=="unlock"){
    if (
trim($param)) if (!checklock($lockfile$param)) fatal("'$vhost_file' is locked!");
    @
unlink($lockfile);
    exit;
}

scan_servernames();

if (
$debug){
    print 
"Vhost '$vhost_file' Line " . ($vhost_start+1) ." - " . ($vhost_end+1) ."\n";
    print 
"ServerName: $servername\n";
    print 
"ServerAliases:";
    
reset($serveralias);
    while (list(
$n,$v)=each($serveralias)) print $v";
    print 
"\n";
}



if (
$action=="getserveraliases" || $action=="getnames" || $action=="getservername"){
    
$cnt=0;
    if (
$action=="getnames" || $action=="getservername"){
    print 
"$servername";
    
$cnt=1;
    }
    if (
$action!="getservername"){
    
reset($serveralias);
    while (list(
$n,$v)=each($serveralias)) {
        if (
$cnt>0) print " ";
        print 
"$v";
        
$cnt++;
    }
    }
    print 
"\n";

}
else if (
$action=="getsection"){
    if (
$param2){
    if (!
writelock($lockfile$param2)) fatal("'$vhost_file' is locked!");
    }
    if (
$param!="-") if (!($fp=@fopen($param"w+"))) fatal("Can't open '$param'");
    
$file=file($vhost_file);
    for (
$a=$vhost_start;$a<=$vhost_end;$a++){
    if (
$param!="-")  fputs($fp$file[$a]); else print $file[$a];
    }
    if (
$param!="-"fclose($fp);
} else if (
$action=="setsection"){
    if (!
writelock($lockfile$param2)) fatal("'$vhost_file' is locked!");

    if (
$param=="-"$param="php://stdin";
    if (!(
$new=@file("$param"))) fatal("Can't open '$param'");
    if (!(
$old=@file("$vhost_file"))) fatal("Can't open '$vhost_file'");
    if (!(
$fp=@fopen($vhost_file.".tmp""w+"))) fatal("Can't open '$vhost_file.tmp' for writing");

    
// write stuff before old vhost-section
    
for ($a=0;$a<$vhost_start;$a++){
    
fputs($fp$old[$a]);
    }

    
// write new stuff
    
for ($a=0;$a<count($new);$a++){
    
fputs($fp$new[$a]);
    }

    
// write old stuff after new vhost-section
    
for ($a=$vhost_end+1;$a<count($old);$a++){
    
fputs($fp$old[$a]);
    }

    
fclose($fp);

    @
unlink($vhost_file) || fatal("Can't unlink '$vhost_file'!");
    
rename($vhost_file.".tmp"$vhost_file);

    
unlock($lockfile);

} else if (
$action=="setnames"){
    if (!
trim($param)) fatal("No Name is impossible!");
    if (!
file_exists($vhost_file)) fatal("$vhost_file does not exists");


    
//prepare
    
$names=Array();
    for (
$i=3;$i<count($_SERVER['argv']);$i++){
    
$names=array_merge($names,$names=split("[ \t]"$_SERVER['argv'][$i]));
    }
    
reset($names);
    
$new_servername="";
    
$new_serveralias=array();
    
$cnt=0;
    while (list(
$n,$vv)=each($names)){
    if (
$cnt==0$new_servername=trim($vv);
    else 
$new_serveralias[]=trim($vv);
    
$cnt++;
    }

    if (!
writelock($lockfile"setnames"+time())) fatal("'$vhost_file' is locked!");

    @
unlink($vhost_file.".tmp");
    if (!(
$f=@file("$vhost_file"))) fatal("Can't open '$vhost_file'");
    if (!(
$fp=@fopen($vhost_file.".tmp""w+"))) fatal("Can't open '$vhost_file.tmp' for writing");

    
// write stuff before old vhost-section
    
for ($a=0;$a<$vhost_start;$a++){
    
fputs($fp$f[$a]);
    }
    
// scan 
    
$aliasline=0;
    for (
$a=$vhost_start;$a<=$vhost_end;$a++){
    
$v=$f[$a];
    if (
preg_match(
            
"/^[[:space:]]*servername"
            
."[[:space:]]+([^#]*)([[:space:]]+|$)/i"$v$erg)){
        
$f[$a]="ServerName $new_servername\n";
        
$nameline=$a;
    } else if (
preg_match(
            
"/^[[:space:]]*serveralias"
            
."[[:space:]]*([^#]+)/i"$v$erg)){
        if (
$aliasline>0){
        
//ups, there are more aliaslines, so kick them
        
$f[$a]="";
        } else 
$aliasline=$a;
    }
    }
    
//print "Aliasline: $aliasline / Nameline: $nameline\n";
    // write new stuff
    
for ($a=$vhost_start;$a<=$vhost_end;$a++){
    
//print "$a : $f[$a]";
    
if ($a>&& $a==$aliasline && count($new_serveralias)==0) continue;
    if (
count($new_serveralias)>&& $a>&& $a==$aliasline ){ //replace
        
fputs($fp"ServerAlias");
        
reset($new_serveralias);
        while (list(
$n,$vv)=each($new_serveralias)) fputs($fp" ".$vv);
        
fputs($fp"\n");
        continue;
    }
    if (
$f[$a]){
        
fputs($fp$f[$a]);
    }
    if (
count($new_serveralias)>&& !$aliasline && $a==$nameline   ){ //insert
        
fputs($fp"ServerAlias");
        
reset($new_serveralias);
        while (list(
$n,$vv)=each($new_serveralias)) fputs($fp" ".$vv);
        
fputs($fp"\n");
        
$aliasline=0;
    }
    }

    
// write old stuff after new vhost-section
    
for ($a=$vhost_end+1;$a<count($old);$a++){
    
fputs($fp$old[$a]);
    }

    
fclose($fp);

    
unlink($vhost_file) || fatal("Can't unlink '$vhost_file'!");
    @
rename($vhost_file.".tmp"$vhost_file);

    
unlock($lockfile);


// scan_servernames
else if ($action=="getline"){
    if (!
trim($param)) fatal("No Names given");
    if (!
file_exists($vhost_file)) fatal("$vhost_file does not exists");


    
$param=trim($param);
    
$paramrx=rx_quote($param);

    if (!(
$f=@file("$vhost_file"))) fatal("Can't open '$vhost_file'");

    for (
$a=$vhost_start;$a<=$vhost_end;$a++){
    
$v=$f[$a];
    if (
preg_match(
            
"/^[[:space:]]*$paramrx"
            
."[[:space:]]+([^#]*)([[:space:]]+|$)/i"$v$erg)){
        
$erg=trim($erg[1]);
        print 
$erg."\n";
    }
    }

// getline
else if (substr($action,3)=="line"){
    if (
$action=="setline"$what=1;
    else if (
$action=="addline"$what=2;
    else if (
$action=="modline"$what=3;
    else if (
$action=="delline"$what=4;
    else if (
$action=="remline"$what=5;
    else { 
usage(); exit(1); }

    if (!
trim($param)) fatal("No Names is impossible!");
    if (!
file_exists($vhost_file)) fatal("$vhost_file does not exists");

    
// check
    
$param=trim($param);

    if (!(
$f=@file("$vhost_file"))) fatal("Can't open '$vhost_file'");

    
// scan 
    
$paramrx=rx_quote($param);
    
$inline=Array();
    if (
$what!=2){
    for (
$a=$vhost_start;$a<=$vhost_end;$a++){
        
$v=$f[$a];
        if (
preg_match(
                
"/^[[:space:]]*$paramrx"
                
."[[:space:]]+([^#]*)$/i"$v$erg)){
        
//$f[$a]="ServerName $new_servername\n";
        //iprint "Found: $v";
        
$inline[]=$a;
        } 
    }
    }
    if (
$what>&& !count($inline) ){
    
/* mod/del/rem can only be done if line was found */
    
exit;
    }


    if (!
writelock($lockfile"xxxline"+time())) fatal("'$vhost_file' is locked!");

    @
unlink($vhost_file.".tmp");
    if (!(
$fp=@fopen($vhost_file.".tmp""w+"))) fatal("Can't open '$vhost_file.tmp' for writing");

    
// write stuff before old vhost-section
    
for ($a=0;$a<$vhost_start;$a++){
    
fputs($fp$f[$a]);
    }

    
// write new stuff
    
for ($a=$vhost_start;$a<=$vhost_end;$a++){
    if (
count($inline) && in_array($a$inline)){
        
//print "Here again: $f[$a]";
        
switch ($what){
        case 
5/* rem */
            
$f[$a]="# ".$f[$a];
            break;
        case 
1/* set */
        
case 3/* mod */
            
$f[$a]=($param3 $param3 $param) . $param2\n";
            break;
        case 
4/* del */
            
unset($f[$a]);
            break;
        }
    }
    if (isset(
$f[$a])) fputs($fp$f[$a]);
    if (
$a==$vhost_end-&& count($inline)<&& $what<3fputs($fp, ($param3 $param3 $param) .$param2\n");
    }

    
// write old stuff after new vhost-section
    
for ($a=$vhost_end+1;$a<count($old);$a++){
    
fputs($fp$old[$a]);
    }

    
fclose($fp);

    
unlink($vhost_file) || fatal("Can't unlink '$vhost_file'!");
    @
rename($vhost_file.".tmp"$vhost_file);

    
unlock($lockfile);


// ???line

else {
    
usage();
    exit;
}

function 
usage(){
    global 
$_SERVER;
    print 
"APAMOD 0.4 - Utility for apache virtual host configuration\n";
    print 
"(C) 2002-2010 by Folke Ashberg <folke@ashberg.de>\n";
    print 
"\n";
    print 
"APAMOD comes with ABSOLUTELY NO WARRANTY\n";
    print 
"This is free software, and you are welcome to redistribute it\n";
    print 
"under certain conditions; se LICENCE for details\n";
    print 
"\n";
    print 
"Usage: ".basename($_SERVER['argv'][0])." <DOMAIN> <ACTION> [<PARAM> <PARAM2> ...] \n";
    print 
"\n";
    print 
"Actions:\n";
    print 
"    getservername    Print the ServerName\n";
    print 
"    getserveraliases Print Aliases\n";
    print 
"    getnames         Print ServerName and Aliases\n";
    print 
"    setnames         Set new ServerName and Aliases\n";
    print 
"    getsection       Write VH-Section into file <PARAM> [lock with <PARAM2>]\n";
    print 
"    setsection       Write VH-Section from file <PARAM> [unlock using <PARAM2>]\n";
    print 
"    getline          Get line(s) starting with <PARAM>\n";
    print 
"    ___line          Modify the line(s) starting with <PARAM>\n";
    print 
"        setline      Change the line(s) to <PARAM2>, add if not exists\n";
    print 
"                      Name is changed to <PARAM3> if given\n";
    print 
"        modline      Modify the line(s) to <PARAM2>, only if found\n";
    print 
"                      Name is changed to <PARAM3> if given\n";
    print 
"        addline      Add a line named <PARAM> [<PARAM2>]\n";
    print 
"        delline      Delete the line(s)\n";
    print 
"        remline      Remark the line(s)\n";
    print 
"   unlock            Unlock vh-file [using <PARAM>]\n";
    print 
"  Special Domains: (no operations possible)\n";
    print 
"    getallnames      Get ALL ServerNames\n";
    print 
"    getallvhosts     Get ALL ServerNames and ServerAliases\n";  
    print 
"\n";
}


?>