<?php
/*
 +--------------------------------------------------------------------------+
 | phpMyBackupPro                                                           |
 +--------------------------------------------------------------------------+
 | Copyright (c) 2004-2007 by Dirk Randhahn                                 |                               
 | http://www.phpMyBackupPro.net                                            |
 | version information can be found in definitions.php.                     |
 |                                                                          |
 | 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.|
 +--------------------------------------------------------------------------+
*/


// standard debug function
function PMBP_debug($object) {
    echo "<pre>";
    print_r($object);
    echo "</pre>";
}

// generates javascript 'select all in input select' link
function PMBP_set_select($form,$select,$link){
    return "<a href=\"\" onclick=\"setSelect('".$form."','".$select."'); return false;\">".$link."</a>";
}


// generates javascript PMBP_pop_up link
function PMBP_pop_up($path,$link,$type,$title_attr=""){
    return "<a href='javascript:popUp(\"".$path."\",\"".$type."\",false,\"\")' title=\"".$title_attr."\">".$link."</a>";
}


// generates event hanlders to change the border color in a td.list list
function PMBP_change_color($color1,$color2){
    return "onmouseout=\"changeColor(this, '".$color1."');\" onmouseover=\"changeColor(this, '".$color2."');\"";
}

// function to execute the sql queries provided by the file handler $file
// $file can be a gzopen() or open() handler, $con is the database connection
// $linespersession says how many lines should be executed; if false, all lines will be executed
function PMBP_exec_sql($file,$con,$linespersession=false,$noFile=false) {
    $query="";
    $queries=0;
    $error="";
    if (isset($_GET["totalqueries"])) $totalqueries=$_GET["totalqueries"]; else $totalqueries=0;
    if (isset($_GET["start"])) $linenumber=$_GET["start"]; else $linenumber=$_GET['start']=0;
    if (!$linespersession) $_GET['start']=1;
    $inparents=false;
    $querylines=0;

    // $tableQueries and $insertQueries only count this session
    $tableQueries=0;
    $insertQueries=0;

    // stop if a query is longer than 300 lines long
    $max_query_lines=300;

    // lines starting with these strings are comments and will be ignored
	$comment[0]="#";
	$comment[1]="-- ";

    while (($linenumber<$_GET["start"]+$linespersession || $query!="") && ($dumpline=gzgets($file,65536)))               
    {
    	// increment $_GET['start'] when $linespersession was not set
    	// so all lines of $file will be exeuted at once
    	if (!$linespersession) $_GET['start']++;
    	  
        // handle DOS and Mac encoded linebreaks
        $dumpline=ereg_replace("\r\n$","\n",$dumpline);
        $dumpline=ereg_replace("\r$","\n",$dumpline);

        // skip comments and blank lines only if NOT in parents    
        if (!$inparents) {
            $skipline=false;
            foreach ($comment as $comment_value) {
                if (!$inparents && (trim($dumpline)=="" || strpos ($dumpline,$comment_value)===0)) {
                    $skipline=true;
                    break;
                }
            }
            if ($skipline) {
                $linenumber++;
                continue;
            }
        }

        // remove double back-slashes from the dumpline prior to count the quotes ('\\' can only be within strings)  
        $dumpline_deslashed=str_replace("\\\\","",$dumpline);

        // count ' and \' in the dumpline to avoid query break within a text field ending by ;
        // please don't use double quotes ('"')to surround strings, it wont work
        $parents=substr_count($dumpline_deslashed,"'")-substr_count($dumpline_deslashed,"\\'");
        if ($parents%2!=0) $inparents=!$inparents;

        // add the line to query
        $query.=$dumpline;

        // don't count the line if in parents (text fields may include unlimited linebreaks)  
        if (!$inparents) $querylines++;
          
        // stop if query contains more lines as defined by $max_query_lines    
        if ($querylines>$max_query_lines) {
            $error=sprintf(BI_WRONG_FILE."\n",$linenumber,$max_query_lines);
            break;
        }

        // execute query if end of query detected (; as last character) AND NOT in parents
        if (ereg(";$",trim($dumpline)) && !$inparents) {
            if (!mysql_query(trim($query),$con)) {
                $error=SQ_ERROR." ".($linenumber+1)."<br>".nl2br(htmlentities(trim($query)))."\n<br>".htmlentities(mysql_error());
                break;
            }
            
            if (strtolower(substr(trim($query),0,6))=="insert") $tableQueries++;
				elseif (strtolower(substr(trim($query),0,12))=="create table") $insertQueries++; 
            $totalqueries++;
            $queries++;
            $query="";
            $querylines=0;
        }            
        $linenumber++;
    }
    return array("queries"=>$queries,"totalqueries"=>$totalqueries,"linenumber"=>$linenumber,"error"=>$error,"tableQueries"=>$tableQueries,"insertQueries"=>$insertQueries);
}


// generates a dump of $db database
// $tables and $data set whether tables or data to backup. $comment sets the commment text
// $drop and $zip tell if to include the drop table statement or dry to pack
function PMBP_dump($db,$tables,$data,$drop,$zip,$comment) {
    global $CONF;
    global $PMBP_SYS_VAR;
    $error=FALSE;
    
    // set max string size before writing to file
    if (@ini_get("memory_limit")) $max_size=900000*ini_get("memory_limit");
        else $max_size=$PMBP_SYS_VAR['memory_limit'];
    
    // set backupfile name
    $time=time();
    /*if ($zip=="gzip") $backupfile=$db.".".$time.".sql.gz";
        else $backupfile=$db.".".$time.".sql";
    $backupfile=PMBP_EXPORT_DIR.$backupfile;*/
    
/***************************** linea nueva *///////
    if ($zip=="gzip") $backupfile=inGenioX_str_antes_resto($db,INGENIO_PREFIJO_DB,2).".".$time.".sql.gz";
        else $backupfile=inGenioX_str_antes_resto($db,INGENIO_PREFIJO_DB,2).".".$time.".sql";
    $backupfile=PMBP_EXPORT_DIR.$backupfile;
/***************************** linea nueva *///////
                    
    if ($con=@mysql_connect($CONF['sql_host'],$CONF['sql_user'],$CONF['sql_passwd'])) {

        //create comment
        $out="# MySQL dump of database '...".inGenioX_str_antes_resto($db,INGENIO_PREFIJO_DB,2)."' on host '".$CONF['sql_host']."'\n";
        $out.="# backup date and time: ".strftime($CONF['date'],$time)."\n";
        $out.="# built by phpMyBackupPro ".PMBP_VERSION."\n";
        $out.="# ".PMBP_WEBSITE."\n";
/***************************** linea nueva *///////
        $out.="# ".INGENIO_CREDITOS_SQL."\n\n";
/***************************** linea nueva *///////

        // write users comment
        if ($comment) {
            $out.="# comment:\n";
            $comment=preg_replace("'\n'","\n# ","# ".$comment);
            foreach(explode("\n",$comment) as $line) $out.=$line."\n";
            $out.="\n";
        }

        // print "use database" if more than one databas is available
        if (count(PMBP_get_db_list())>1) {
            $out.="CREATE DATABASE IF NOT EXISTS `".$db."`;\n\n";
            $out.="USE `".$db."`;\n";
        }
        
        // select db
        @mysql_select_db($db);        
        
        // get auto_increment values and names of all tables
        $res=mysql_query("show table status");
        $all_tables=array();
        while($row=mysql_fetch_array($res)) $all_tables[]=$row;

        // get table structures
        foreach ($all_tables as $table) {
            $res1=mysql_query("SHOW CREATE TABLE `".$table['Name']."`");
            $tmp=mysql_fetch_array($res1);
            $table_sql[$table['Name']]=$tmp["Create Table"];
        }

        // find foreign keys
        $fks=array();
        if (isset($table_sql)) {
            foreach($table_sql as $tablenme=>$table) {
                $tmp_table=$table;
                // save all tables, needed for creating this table in $fks
                while (($ref_pos=strpos($tmp_table," REFERENCES "))>0) {
                    $tmp_table=substr($tmp_table,$ref_pos+12);
                    $ref_pos=strpos($tmp_table,"(");
                    $fks[$tablenme][]=substr($tmp_table,0,$ref_pos);
                }
            }
        }

        // order $all_tables and check for ring constraints
        $all_tables_copy = $all_tables;
        $all_tables=PMBP_order_sql_tables($all_tables,$fks);
		$ring_contraints = false;

		// ring constraints found
        if ($all_tables===false) {
        	$ring_contraints = true;
        	$all_tables = $all_tables_copy;
        	
        	$out.="\n# ring constraints workaround\n";
        	$out.="SET FOREIGN_KEY_CHECKS=0;\n"; 
			$out.="SET AUTOCOMMIT=0;\n";
			$out.="START TRANSACTION;\n"; 
        }
        unset($all_tables_copy);

        // as long as no error occurred
        if (!$error) {
            foreach ($all_tables as $row) {
                $tablename=$row['Name'];
                $auto_incr[$tablename]=$row['Auto_increment'];

                // don't backup tables in $PMBP_SYS_VAR['except_tables']
                if (in_array($tablename,explode(",",$PMBP_SYS_VAR['except_tables'])))
                    continue;

                $out.="\n\n";
                // export tables
                if ($tables) {
                    $out.="### structure of table `".$tablename."` ###\n\n";
                    if ($drop) $out.="DROP TABLE IF EXISTS `".$tablename."`;\n\n";
                    $out.=$table_sql[$tablename];

                    // add auto_increment value
                    if ($auto_incr[$tablename]) {
                        $out.=" AUTO_INCREMENT=".$auto_incr[$tablename];
                    }
                    $out.=";";
                }
                $out.="\n\n\n";

                // export data
                if ($data && !$error) {
                    $out.="### data of table `".$tablename."` ###\n\n";

                    // check if field types are NULL or NOT NULL
                    $res3=mysql_query("show columns from `".$tablename."`");

                    $res2=mysql_query("select * from `".$tablename."`");
                    for ($j=0;$j<mysql_num_rows($res2);$j++){
                        $out .= "insert into `".$tablename."` values (";
                        $row2=mysql_fetch_row($res2);
                        // run through each field
                        for ($k=0;$k<$nf=mysql_num_fields($res2);$k++) {
                            // identify null values and save them as null instead of ''
                            if (is_null($row2[$k])) $out .="null"; else $out .="'".mysql_escape_string($row2[$k])."'";
                            if ($k<($nf-1)) $out .=", ";
                        }
                        $out .=");\n";

                        // if saving is successful, then empty $out, else set error flag
                        if (strlen($out)>$max_size) {
                            if ($out=PMBP_save_to_file($backupfile,$zip,$out,"a")) $out=""; else $error=TRUE;
                        }
                    }

                // an error occurred! Try to delete file and return error status
                } elseif ($error) {
                    @unlink("./".PMBP_EXPORT_DIR.$backupfile);
                    return FALSE;
                }

                // if saving is successful, then empty $out, else set error flag
                if (strlen($out)>$max_size) {
                    if ($out=PMBP_save_to_file($backupfile,$zip,$out,"a")) $out=""; else $error=TRUE;
                }
            }
            
        // an error occurred! Try to delete file and return error status
        } else {
            @unlink("./".$backupfile);
            return FALSE;
        }
        
        // if db contained ring constraints        
		if ($ring_contraints) {
			$out.="\n\n# ring constraints workaround\n";
			$out .= "SET FOREIGN_KEY_CHECKS=1;\n"; 
			$out .= "COMMIT;\n"; 
		}

		// save to file
        if ($backupfile=PMBP_save_to_file($backupfile,$zip,$out,"a")) {
            if ($zip!="zip") return basename($backupfile);
        } else {
            @unlink("./".$backupfile);
            return FALSE;
        }
        
        // create zip file in file system
    	include_once("pclzip.lib.php");
    	$pclzip = new PclZip($backupfile.".zip");
    	$pclzip->create($backupfile,PCLZIP_OPT_REMOVE_PATH,PMBP_EXPORT_DIR);    	

        // remove temporary plain text backup file used for zip compression
        @unlink(substr($backupfile,0,strlen($backupfile)));
         
        if ($pclzip->error_code==0) {
        	return basename($backupfile).".zip";
        } else {
        	// print pclzip error message
	        echo "<div class=\"red\">pclzip: ".$pclzip->error_string."</div>";

	        // remove temporary plain text backup file 
	    	@unlink(substr($backupfile,0,strlen($backupfile)-4));
	        @unlink("./".$backupfile);
	        return FALSE;
        }

    } else {
        return "DB_ERROR";
    }
}


// orders the tables in $tables according to the constraints in $fks
// $fks musst be filled like this: $fks[tablename][0]=needed_table1; $fks[tablename][1]=needed_table2; ...
function PMBP_order_sql_tables($tables,$fks) {
    // do not order if no contraints exist
    if (!count($fks)) return $tables;

    // order
    $new_tables=array();
    $existing=array();
    $modified=TRUE;
    while(count($tables) && $modified==TRUE) {
        $modified=FALSE;
        foreach($tables as $key=>$row) {
            // delete from $tables and add to $new_tables
            if (isset($fks[$row['Name']])) {
                foreach($fks[$row['Name']] as $needed) {
                    // go to next table if not all needed tables exist in $existing
                    if(!in_array($needed,$existing)) continue 2;
                }
            }
            
            // delete from $tables and add to $new_tables
            $existing[]=$row['Name'];
            $new_tables[]=$row;
            prev($tables);
            unset($tables[$key]);
            $modified=TRUE;
        }
    }

    if (count($tables)) {
        // probably there are 'circles' in the constraints, because of that no proper backups can be created
        // This will be fixed sometime later through using 'alter table' commands to add the constraints after generating the tables.
        // Until now I just add the lasting tables to $new_tables, return them and print a warning
        foreach($tables as $row) $new_tables[]=$row;
        //echo "<div class=\"red_left\">THIS DATABASE SEEMS TO CONTAIN 'RING CONSTRAINTS'. pMBP DOES NOT SUPPORT THEM. PROBABLY THE FOLLOWING BACKUP IS BROKEN!</div>";
        return false;
    }
    return $new_tables;
}

// saves $files backup files on $server ftp server in $path path using $user username and $pass password
function PMBP_ftp_store($files) {
    global $CONF;
    global $PMBP_SYS_VAR;
    $out=FALSE;
    
    // try to connect to server using username and passwort
    if (!$CONF['ftp_server']) {
        $out.="<div class=\"red\">".C_WRONG_FTP."!</div>";
    } elseif (!$conn_id=@ftp_connect($CONF['ftp_server'],$CONF['ftp_port'],$PMBP_SYS_VAR['ftp_timeout'])) {
        $out.="<div class=\"red\">".F_FTP_1." '".$CONF['ftp_server']."'!</div>";
    } else {
        if (!$login_result=@ftp_login($conn_id,$CONF['ftp_user'],$CONF['ftp_passwd'])) {
            $out.="<div class=\"red\">".F_FTP_2." '".$CONF['ftp_user']."'.</div>";
        } else {

            // succesfully connected
            if ($CONF['ftp_pasv']) ftp_pasv($conn_id,TRUE); else ftp_pasv($conn_id,FALSE);
            if (!$CONF['ftp_path']) $path="."; else $path=$CONF['ftp_path'];

            // upload the files
            foreach($files as $filename) {
            	$source_file="./".$filename;
            	if (substr($filename,0,strlen(PMBP_EXPORT_DIR))==PMBP_EXPORT_DIR) $filename = substr($filename,strlen(PMBP_EXPORT_DIR));
                $dest_file=$path."/".$filename;

                // try three times to upload
                $check=FALSE;
                for($i=0;$i<3;$i++)
                    if (!$check) $check=@ftp_put($conn_id,$dest_file,$source_file,FTP_BINARY);
                if (!$check) $out.="<div class=\"red\">".F_FTP_3.": '".$source_file."' -> '".$dest_file."'.</div>\n";
                    else $out.="<div class=\"green\">".F_FTP_4." '".$dest_file."'.</div>\n";
            }

            // close the FTP connection
            if (@function_exists("ftp_close")) @ftp_close($conn_id);
        }
    }
    return $out;
}


// send email with $attachments backup files to $email email using $sitename for sender and subject
function PMBP_email_store($attachments,$backup_info) {
    global $CONF;
    $out=FALSE;
    $lb="\n";
    $all_emails=explode(",",$CONF['email']);
 
 	$mailtext=F_MAIL_2." '".$CONF['sitename']."'.".$lb;
 
 	// send database backups
 	if (is_array($backup_info)) {
	    if ($backup_info['comp']=="gzip") $mailtext.=INF_COMP.": gzip".$lb;
	        elseif ($backup_info['comp']=="zip") $mailtext.=INF_COMP.": zip".$lb;
	            else $mailtext.=INF_COMP.": ".F_NO.$lb;
	    if ($backup_info['drop']) $mailtext.=INF_DROP.": ".F_YES.$lb; else $mailtext.=INF_DROP.": ".F_NO.$lb;
	    if ($backup_info['tables']) $mailtext.=INF_TABLES.": ".F_YES.$lb; else $mailtext.=INF_TABLES.": ".F_NO.$lb;
	    if ($backup_info['data']) $mailtext.=INF_DATA.": ".F_YES.$lb; else $mailtext.=INF_DATA.": ".F_NO.$lb;
	    $mailtext.=INF_COMMENT.":".$lb.$backup_info['comments'];
 	}
 	
 	// send directory backups
 	else {
 		$mailtext.=INF_COMMENT.":".$lb.$backup_info;	
 	}
    srand((double)microtime()*1000000);
    $boundary="=_".md5(uniqid(rand()).microtime());
    $parts[-1]="Content-Type: text/plain; charset=\"".BD_CHARSET_EMAIL."\"".$lb.$lb.$mailtext.$lb;
    for ($i=0;$i<count($attachments);$i++) {
    	$bodies[$i]=file_get_contents($attachments[$i]);
        $bodies[$i]=rtrim(chunk_split(base64_encode($bodies[$i]), 76, $lb)).$lb;
        $parts[$i]="Content-Type: application/zip; name=\"".$attachments[$i].
        "\"".$lb."Content-Transfer-Encoding: base64".$lb."Content-Disposition: attachment; filename=\"".$attachments[$i]."\"".$lb.$lb.$bodies[$i].$lb;
    }

    $encoded['body']="--".$boundary.$lb.implode("--".$boundary.$lb,$parts)."--".$boundary."--".$lb.$lb;
    $headers="From: phpMyBackupPro on ".$CONF['sitename']." <".$all_emails[0].">".$lb."Mime-Version: 1.0".$lb."Content-Type: multipart/mixed;".$lb."\tboundary=\"".$boundary."\"";

    // send to all every addresses
    foreach($all_emails as $email) {
        // verify email
        if (!eregi("^\ *[äöüÄÖÜa-zA-Z0-9_-]+(\.[äöüÄÖÜa-zA-Z0-9\._-]+)*@([äöüÄÖÜa-zA-Z0-9-]+\.)+([a-z]{2,4})$",$email)) {
            $out.="<div class=\"red\">".F_MAIL_1."</div>\n";
            continue;
        }
    }
    
    // create subject
    if (count($CONF['sql_host_s'])) {
        $subject=F_MAIL_4." ".$CONF['sitename']." (".$CONF['sql_host'].", ".$CONF['sql_user'].")";
    } else {
        $subject=F_MAIL_4." ".$CONF['sitename'];
    }

    // send mail
    if (!@mail($CONF['email'],$subject,$encoded['body'],$headers)) $out.="<div class=\"red\">".F_MAIL_5.".</div>\n";
        else $out.="<div class=\"green\">".F_MAIL_6." ".$CONF['email'].".</div>\n";
    
    return $out;
}


// returns present local backup files after deleting backups files 
function PMBP_get_backup_files() {
    global $CONF;
    $delete_files=FALSE;
    $all_files=FALSE;
    $result_files=FALSE;
    $handle=@opendir("./".PMBP_EXPORT_DIR);
    $remove_time=time()-($CONF['del_time']*86400);
    while ($file=@readdir($handle)) {
        if ($file!="." && $file!=".." && preg_match("'\.sql|\.sql\.gz|\.sql\.zip'",$file)) {
            
/***************************** linea nueva *///////
            // don't delete if del_time is not set
            /*if ($CONF['del_time']) {
                if (PMBP_file_info("time",$file)<$remove_time) $delete_files[]=$file; else $all_files[]=$file;
            } else {*/
                $all_files[]=$file;
            //}
/***************************** linea nueva *///////
        }
    }

    // sort descending
    if (is_array($all_files)) rsort($all_files);

    // delete oldest backup files if there are to many for one db
    if (is_array($all_files)) {
        foreach($all_files as $file) {
            if (!isset($counter[$db=PMBP_file_info("db","./".PMBP_EXPORT_DIR.$file)])) $counter[$db]=1; else $counter[$db]++;
/***************************** linea nueva *///////
            /*if ($counter[$db]>$CONF['del_number']) $delete_files[]=$file; else $result_files[]=$file;
            */
            $result_files[]=$file;
/***************************** linea nueva *///////
       }
    }

/***************************** linea nueva *///////
    // now delete the files
    /*if ($delete_files) PMBP_delete_backup_files($delete_files);
	*/
/***************************** linea nueva *///////
	
    // sort ascending
    if (is_array($result_files)) sort($result_files);
    return $result_files;
}


// delete the file(s) in mixed $files from local export dir and remote ftp server
function PMBP_delete_backup_files($files) {
    global $CONF;
    $out="";
    if(!is_array($files)) $files=array($files);
    foreach($files as $file) if (!@unlink("./".PMBP_EXPORT_DIR.$file))
    	$out.="<div class=\"red\">".sprintf(F_DEL_FAILED,$file)."</div>";

    // find and delete all old files from the ftp server
    if ($CONF['ftp_use'] && $CONF['ftp_del']) $out.=PMBP_ftp_del($files);
    return $out;
}


// deletes $files backup files from $server ftp server in $path path using $user username and $pass password
function PMBP_ftp_del($delete_files=array()) {
    global $CONF;
    global $PMBP_SYS_VAR;
    $out=FALSE;

    // try to connect to server using username and passwort
    if (!$CONF['ftp_server']) {
        $out.="<div class=\"red\">".C_WRONG_FTP."</div>";
    } elseif (!$conn_id=@ftp_connect($CONF['ftp_server'],$CONF['ftp_port'],$PMBP_SYS_VAR['ftp_timeout'])) {
        $out.="<div class=\"red\">".F_FTP_1." '".$CONF['ftp_server']."'!</div>";
    } else {
        if (!$login_result=@ftp_login($conn_id,$CONF['ftp_user'],$CONF['ftp_passwd'])) {
            $out.="<div class=\"red\">".F_FTP_2." '".$CONF['ftp_user']."'.</div>";
        } else {

            // succesfully connected
            if ($CONF['ftp_pasv']) ftp_pasv($conn_id,TRUE); else ftp_pasv($conn_id,FALSE);

            // get files in remote directory
            if (!$CONF['ftp_path']) $path="."; else $path=$CONF['ftp_path'];
            $remote_files=ftp_nlist($conn_id,$path);

            if (is_array($remote_files)) {
                // separate filename
                for($i=0;$i<count($remote_files);$i++)
                    if (strrchr($remote_files[$i],"/")) $remote_files[$i]=substr(strrchr($remote_files[$i],"/"),1);
                	
                // don't delete if del_time is false                
                if ($CONF['del_time']) {
                	$remove_time=time()-($CONF['del_time']*86400);
                    foreach($remote_files as $remote_file) {
                        if (substr($remote_file,count($remote_file)-4)!=".sql" &&
                        	substr($remote_file,count($remote_file)-7)!=".sql.gz" &&
                        	substr($remote_file,count($remote_file)-8)!=".sql.zip") continue;
                        if (PMBP_file_info("time",$remote_file)<$remove_time) {
                        	$delete_files[]=$remote_file;
                        } else {
                        	$all_files[]=$remote_file;
                        }
                    }
                } else {
                    $all_files=$remote_files;
                }

                // sort descending
                if (isset($all_files))
                {
	                if (is_array($all_files)) rsort($all_files);

	                // delete oldest backup files if there are to many for one db
	                if (is_array($all_files)) {
	                    foreach($all_files as $file) {
	                        $db=PMBP_file_info("db",$file);
	                        if (!isset($counter[$db])) $counter[$db]=1; else $counter[$db]++;
	                        if ($counter[$db]>$CONF['del_number']) $delete_files[]=$file; else $result_files[]=$file;
	                    }
	                }        
                }
                       
                // delete the files in $delete_files
                if (is_array($delete_files)) {
                    foreach($delete_files as $filename) {
                        $dest_file=$path."/".$filename;
    
                        // try three times to delete
                        $check=FALSE;
                        for($i=0;$i<3;$i++) {
                            if (!$check) $check=@ftp_delete($conn_id,$dest_file);
                        }
                        if (!$check) $out.="<div class=\"red\">".sprintf(F_FTP_5."</div>\n",$dest_file);
                            else $out.="<div class=\"green\">".sprintf(F_FTP_6."</div>\n",$dest_file);
                    }
                }
            }

            // close the FTP connection
            if (@function_exists("ftp_close")) @ftp_close($conn_id);
        }
    }
    return $out;
}

// in dependency on $mode different modes can be selected (see below)
function PMBP_file_info($mode,$path) {
    $filename=ereg_replace(".*/","",$path);
    $parts=explode(".",$filename);

    switch($mode) {
    
        // returns the name of the database a $path backup file belongs to
        case "db":
            return $parts[0];

        // returns the creation timestamp $path backup file
        case "time":
            return $parts[1];
        
        // returns "gz" if $path backup file is gziped
        case "gzip":
            if (isset($parts[3])) if ($parts[3]=="gz") return $parts[3];
        break;
        
        // returns "zip" if $path backup file is ziped
        case "zip":
            if (isset($parts[3])) if ($parts[3]=="zip") return $parts[3];
        break;
        
        // returns type of compression of $path backup file or no
        case "comp":
            if (PMBP_file_info("gzip",$path)) return "gzip"; elseif (PMBP_file_info("zip",$path)) return "zip"; else return F_NO;

        // returns the size of $path backup file
        case "size":
            return filesize($path);

        // returns yes if the backup file contains 'drop table if exists' or no if not
        case "drop":
            while ($line=PMBP_getln($path)) {
                $line=trim($line);
                if (strtolower(substr($line,0,20))=="drop table if exists"){
                	PMBP_getln($path,true);
                	return F_YES;
                } else {
                	$drop=F_NO;
                } 
            }
            PMBP_getln($path,true);
            return $drop;        
        
        // returns yes if the $path backup files contains tables or no if not
        case "tables":
            while ($line=PMBP_getln($path)) {
                $line=trim($line);
                if (strtolower(substr($line,0,12))=="create table"){
                	PMBP_getln($path,true);
                	return F_YES;
                } else {
                	$table=F_NO;
                } 
            }
            PMBP_getln($path,true);
            return $table;

        // returns yes if the $path backup files contains data or no if not
        case "data":
            while ($line=PMBP_getln($path)) {
                $line=trim($line);
                if (strtolower(substr($line,0,6))=="insert") {
                	PMBP_getln($path,true);
                	return F_YES;
                } else {
                	$data=F_NO;
                }
            }
            PMBP_getln($path,true);
            return $data;
        
        // returns the comment stored to the backup file
        case "comment":
            while ($line=PMBP_getln($path)) {
                $line=trim($line);
                if (isset($comment) && substr($line,0,1)=="#") {
                	$comment.=substr($line,2)."<br>";
                } elseif(isset($comment) && substr($line,0,1)!="#") {
                	PMBP_getln($path,true);
                	return $comment;
                }
                if ($line=="# comment:") $comment=FALSE;
            }
            PMBP_getln($path,true);
            if (isset($comment)) return $comment; else return FALSE;
    }
}


// returns the content of the [gziped] $path backup file line by line
function PMBP_getln($path, $close=false, $org_path=false) {
    if (!isset($GLOBALS['lnFile'])) $GLOBALS['lnFile']=null;
    if (!$org_path) $org_path=$path; else $org_path=PMBP_EXPORT_DIR.$org_path;
        
    // gz file
    if(PMBP_file_info("gzip",$org_path)=="gz") {            
    	if (!$close) {
	        if ($GLOBALS['lnFile']==null) {
	            $GLOBALS['lnFile']=gzopen($path, "r");
	        }

	        if (!gzeof($GLOBALS['lnFile'])) {
	           return gzgets($GLOBALS['lnFile']);
	        } else {
	            $close=true;
	        }
    	}

        if ($close) {
			// remove the file handler
			@gzclose($GLOBALS['lnFile']);
            $GLOBALS['lnFile']=null;
            return null;
        }

    // zip file
    } elseif(PMBP_file_info("zip",$org_path)=="zip"){
		if (!$close) {
			if ($GLOBALS['lnFile']==null) {
				// try to guess the filename of the packed file
				// known problem: ZIP file xyz.sql.zip contains file abc.sql which already exists with different content! 
				if(!file_exists(substr($org_path,0,strlen($org_path)-4))) {
					// extract the file
					include_once("pclzip.lib.php");
					$pclzip = new PclZip($path);
					$extracted_file=$pclzip->extract(PMBP_EXPORT_DIR,"");
			        
			        if ($pclzip->error_code!=0) {
			        	// print pclzip error message
				        echo "<div class=\"red\">pclzip: ".$pclzip->error_string."<br>".BI_BROKEN_ZIP."!</div>";
				        return false;
			        } else {
						unset($pclzip);
			        }
				}
			}

			// read the extracted file
			$line=PMBP_getln(substr($org_path,0,strlen($org_path)-4));
			if ($line==null) $close=true;
				else return $line;
    	}

		// remove the temporary file
    	if ($close) {
    		@fclose($GLOBALS['lnFile']);
    		$GLOBALS['lnFile']=null;
    		@unlink(substr($org_path,0,strlen($org_path)-4));
    		return null;
    	}
		
    // sql file
    } else {
		if (!$close) {
	        if ($GLOBALS['lnFile']==null) {
	            $GLOBALS['lnFile']=fopen($path, "r");
	        }
	        
	        if (!feof($GLOBALS['lnFile'])) {
	           return fgets($GLOBALS['lnFile']);
	        } else {
	            $close=true;
	        }
		}
		
		if ($close) {
			// remove the file handler
			@fclose($GLOBALS['lnFile']);
            $GLOBALS['lnFile']=null;
            return null;
        }
    }
}


// determines the best size type for filesize $size and returns array('value'=xxx,'type'=yyy)
function PMBP_size_type($size) {
    $types=array("B","KB","MB","GB");
    for ($i=0; $size>1000; $i++,$size/=1024);
    $result['value']=round($size,2);
    $result['type']=$types[$i];
    return $result;
}


// get recursive directory list
function PMBP_get_dirs($dir,$renew=FALSE) {
    $dirs=FALSE;
    
    // renew date if the 'renew' link was clicked
    if(isset($_GET['update_dir_list'])) $renew=true;
    
    // return existing data
    if($renew) unset($_SESSION['file_system'][$dir]);    
    if(isset($_SESSION['file_system'][$dir])) return $_SESSION['file_system'][$dir];    

    // create directory list
    $dir_handle=@opendir($dir);
    while ($file=@readdir ($dir_handle)) {
        if ($file!="." && $file!="..") {
            if (@is_dir($dir.$file)) {
                $dirs[]=$file."/";
                $tmp=PMBP_get_dirs($dir.$file."/",TRUE);
                if (is_array($tmp)) foreach($tmp as $value) $dirs[]=$file."/".$value;
            }
        }
    }
    $_SESSION['file_system'][$dir]=$dirs;
    return $dirs;
}


// get list of all files in directory
function PMBP_get_files($dir) {
    global $CONF;
    
    $dirs=array();
    $dir=trim($dir);
    if ($dir_handle=@opendir($dir)) {
        while (FALSE!==($file=readdir($dir_handle))) {
        if ($file!="." && $file!="..") {
                if (!is_dir($dir.$file)) {
                $dirs[]=$dir.$file;
                // recursive listing of files
                } elseif($CONF['dir_rec']) {
                    $tmp=PMBP_get_files($dir.$file."/");
                    if (is_array($tmp)) foreach($tmp as $value) $dirs[]=$value;
                }
            }
        }
        @closedir($dir_handle);
    }
    return $dirs;
}


// transfer files $files to FTP servers dirs and create missing folders
function PMBP_save_FTP($files, $packed=false) {
    global $CONF;
    global $PMBP_SYS_VAR;
    $out=FALSE;

    // try to connect to server using username and passwort
    if (!$CONF['ftp_server']) {
        $out.="<div class=\"red\">".C_WRONG_FTP."</div>";
    } elseif (!$conn_id=@ftp_connect($CONF['ftp_server'],$CONF['ftp_port'],$PMBP_SYS_VAR['ftp_timeout'])) {
        $out.="<div class=\"red\">".F_FTP_1." '".$CONF['ftp_server']."'!</div>";
    } else {
        if (!$login_result=@ftp_login($conn_id,$CONF['ftp_user'],$CONF['ftp_passwd'])) {
            $out.="<div class=\"red\">".F_FTP_2." '".$CONF['ftp_user']."'.</div>";
        } else {
        	
            // succesfully connected -> set passive and change to the right path
            if ($CONF['ftp_pasv']) ftp_pasv($conn_id,TRUE); else ftp_pasv($conn_id,FALSE);
            if (!$CONF['ftp_path']) $path="."; else $path=$CONF['ftp_path'];
            @ftp_chdir($conn_id,$path);            
            
			// backup as one ZIP file			
            if ($packed) {

				include_once("pclzip.lib.php");
	            $filename=$CONF['sitename'].".".time().".zip";
	            $pclzip = new Pclzip(PMBP_EXPORT_DIR.$filename);
				$pclzip->create($files);
	
	            // try three times to upload zip files
	            $check=FALSE;
	            for($i=0;$i<3;$i++) {
	            	if (!$check) $check=ftp_put($conn_id,$filename,PMBP_EXPORT_DIR.$filename,FTP_BINARY);
	            }	            
	            if ($check) {
	            	// adjust file permissions on ftp server
	            	//ftp_chmod($conn_id,substr(sprintf('%o', fileperms(PMBP_EXPORT_DIR.$filename)), -4),$filename);
	            	$out.="<div class=\"green\">".F_FTP_4." '".$filename."'.</div>\n";
	            } else {
	            	$out.="<div class=\"red\">".F_FTP_3.".</div>\n";
	            }
				@unlink(PMBP_EXPORT_DIR.$filename);
			
			// backup each file
            } else {            
	            // create all missing folders
	            foreach($files as $filepath) {
	                if ($filepath=trim($filepath)) {
	                    $folders=explode("/",$filepath);
	                    $filename=array_pop($folders);
	                    $deep=0;
	                    $all_folders="";
	                    $all_folders_local="";
	                    foreach($folders as $folder) {
	                    	$all_folders_local.=$folder."/";
	                        if ($folder != "." && $folder != "..") {
	                            if (!@ftp_chdir($conn_id,$folder)) {
	                                @ftp_mkdir($conn_id,$folder);
	                                @ftp_chdir($conn_id,$folder);
	                            }
								// adjust directory permissions
								//ftp_chmod($conn_id,substr(sprintf('%o', fileperms("../".$folder)), -4),"../".$folder);
	                            $all_folders.=$folder."/";
	                            $deep++;
	                        }
	                    }

	                    // change back to $path
	                    $rel_path="";
	                    for ($i=0;$i<$deep;$i++) $rel_path.="../";
	                    @ftp_chdir($conn_id,$rel_path);

	                    // define the source and destination pathes
	                    $dest_file=$all_folders.$filename;
	                    $source_file="./".$filepath;
	
	                    // try three times to upload
	                    $check=FALSE;

	                    for($i=0;$i<3;$i++) if (!$check) $check=@ftp_put($conn_id,$dest_file,$source_file,FTP_BINARY);
	                    if ($check) {
	                    	// adjust file permissions on ftp server
	            			//ftp_chmod($conn_id,substr(sprintf('%o', fileperms($source_file)), -4),$dest_file);
	                    	$out.="<div class=\"green\">".F_FTP_4." '".$dest_file."'.</div>\n";
	                    } else {
							$out.="<div class=\"red\">".F_FTP_3.": '".$source_file."' -> '".$dest_file."'.</div>\n";
	                    }
	                }
	            }

            }
			
            // close the FTP connection
            if (@function_exists("ftp_close")) @ftp_close($conn_id);
        }
    }
    return $out;
}


// login module
function PMBP_auth () {
    header("WWW-Authenticate: Basic realm=\"phpMyBackupPro\"");
    header("HTTP/1.0 401 Unauthorized");
    echo LI_MSG."\n";
}
?>
