Total Pageviews

Monday, 8 April 2013

PHP制作MySql的安装文件

为了对用户更友好,我们会给一个网站做一个安装文件的程序,用可视化界面来引导安装。那么如何来用PHP制作MySql的安装文件呢?
实现这个程序,先要了解清楚原理。一个PHP网页要运行,一般都会基于一个数据库,最佳选择就是MySql,那么安装就是用PHP来执行SQL语句建立数据表的过程,其中可以包括插入一些默认的数据。像MySql导出的数据文件是都可执行的SQL语句(其中还有注释信息),于是我们可以把这些语句用正则表达式分为一条一条的来执行,碰到是数据表的,就提示用户正在安装该表,表名一并显示出来。安装文件执行完毕之后,一个网站便可以运行了。
那么如何来实现具体的功能呢?我写了一个程序,并结合JS定位安装时的数据表信息的滚动条始终在底部、制作了显示安装的进度条。
下面是整个页面的源代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>安装向导</title>
<style type="text/css">
* { margin: 0; padding: 0; }
label { width: 200px; float: left; }
p { margin-bottom: 14px; }
h1 { font-size: 20px; background: #888; color: #fff; height: 37px; line-height: 37px; margin-bottom: 10px; }
h2 { font-size: 100%; margin-bottom: 10px; }
#wrapper { width: 500px; height: 250px; padding: 15px 10px; border: 1px solid #ccc; overflow: auto; }
#progress_w { width: 500px; height: 18px; border: 1px solid #333; margin-bottom: 10px; }
#progress { height: 18px; }
</style>
</head>

<body>
<h1>安装向导</h1>
<?php
/*安装的第一步*/
if(!$_POST['step']||$_POST['step']=='1'){
?>
<h2>开始安装</h2>
<form action="install.php" method="post">
    <p><label>服务器地址:</label><input type="text" name="host" value="localhost" />* 一般为localhost</p>
    <p><label>服务器用户名:</label><input type="text" name="name_s" />*</p>
    <p><label>服务器用户密码:</label><input type="text" name="pass" /> 如果没有设置就不用填</p>
    <p><label>数据库名称:</label><input type="text" name="database" />*</p>
    <p><label>数据表前缀:</label><input type="text" name="table_prefix" /> 如果不填就为qxhtml_</p>
    <p><input type="hidden" name="step" value="2" /></p>
    <p><input type="submit" value="下一步" name="ok" /></p>
</form>
<?php
/*安装的第二步*/
}elseif($_POST['step']=='2'){
  $host = trim($_POST['host']);
  $name = trim($_POST['name_s']);
  $pass = trim($_POST['pass']);
  $database = trim($_POST['database']);
  $table_prefix = trim($_POST['table_prefix']) ? trim($_POST['table_prefix']) : 'qxhtml_';
  
  if($host==''||$name==''||$database==''){
    echo '<p>请确认必填写是否填写</p>','<p><input type="button" value="上一步" onclick="history.back()" /></p>';
    exit();
  }
  
  $conn = @mysql_connect($host,$name,$pass) or die('
    <p>请确认服务器地址、服务器用户名、服务器用户密码是否正确!</p>
    <p><input type="button" value="上一步" onclick="history.back()" /></p>
  ');

  mysql_query("CREATE DATABASE IF NOT EXISTS `".$database."`") or die(mysql_error());
  mysql_select_db($database,$conn) or die("没有该数据库");
  mysql_query("set names 'GBK'");
  
  $file = 'test.sql';
  echo '<h2 id="prompt">正在安装,请稍等...</h2>',
     '<div id="progress_w"><div id="progress"></div></div>',
     '<div id="wrapper"><div id="info">';
  if(file_exists($file)){
    $handle = fopen($file,'r');
    $buffer = fread($handle,filesize($file));
    fclose($handle);
    $buffer = str_replace('{table_prefix}',$table_prefix,$buffer);
    $arr = explode(";\r",$buffer);
    //出栈,删除最后一个空SQL语句的数组
    array_pop($arr);
    //计算一共有多少张表
    $total_table = preg_match_all("/CREATE TABLE `(.*)` /i",$buffer,$a);
    //计数器
    $n = 0;
    //遍历开割开的SQL语句并执行
    foreach($arr as $query){
      //安装进度条的宽度
      $width = 500;
      mysql_query($query) or die(mysql_error());
      //匹配建立表的SQL语句
      $is = preg_match("/CREATE TABLE `(.*)` /i",$query,$arr_preg);
      if($is){
        $n++;
        $progress = ceil(($n/$total_table)*$width);
        echo '正在创建表 ',$arr_preg[1],'... <font color=red>成功</font><br />',
           '<script type="text/javascript">',
             'var wrapper = document.getElementById("wrapper");',
             'var height = wrapper.clientHeight;',
            'wrapper.scrollTop = document.getElementById("info").offsetHeight + 30 - height;',
            'var progress = document.getElementById("progress");',
            'progress.style.background = "#999";',
            'progress.style.width = "',$progress,'px"',
           '</script>';
        //循环一次显示一次
        flush();
      }
    }
    echo '</div></div>';
  }else{
    echo 'SQL的导入文件不存在,安装不无继续!',dirname(__FILE__),'/test.sql';
    exit();
  }
  
  $file = 'config.php';
  //把提交过来的表单信息写入配置文件之中
  if(file_exists($file)){
    $handle = fopen($file,'r');
    $buffer = fread($handle,filesize($file));
    fclose($handle);
    $mode = array('#host#','#name#','#pass#','#database#');
    $subject = array($host,$name,$pass,$database);
    $buffer = str_replace($mode,$subject,$buffer);
    $handle = fopen($file,'w');
    fwrite($handle,$buffer);
    fclose($handle);
  }
  
  echo '<script type="text/javascript"> document.getElementById("prompt").innerHTML = "安装完成^_^";</script>';
  
}
?>
</body>
</html>
首先是用一个if语句判断$_POST['step']的值,如果没有值或是1的话就只显示表单的界面,如果值为2的话进入安装的第二步,因为在表单中有一个隐藏域名为step,赋给它值为2,只要提交后就会进入安装的第二步。
在第二个步骤中,先对表单提交过来的数据进行校验,有不符合规则的停止程序往下执行,并给一个按钮让户用返回重新填写。所有的数据全部校验通过后,再做好数据库的连接,建立一个数据库,判断一个test.sql的文件是否存在(这个文件是由建立表、插入一些默认数据的SQL语 句组成的),如果不存在的话停止安装程序,提示用户安装不能继续。如果test.sql该文件存在的话,用fopen()、fread()函数读出 test.sql文件里的内容,把里面前缀为{table_prefix}内容替换为$table_prefix的值(test.sql文件的制作视频里 有讲解,这个很简单,就是替换),该值如果表单里填了就为表单传过来的值,没填的话就为qxhtml_。接着再用explode的函数以";\r"分割 test.sql文件里的内容,分成了一条一条可执行的SQL语 句,被分割出的数组,最后一个是空的执行语句,array_pop()出栈,去掉最后一个数组元素,当然要摸拟出安装进度条的效果,还需要用正则匹配出 test.sql里的内容有多少句创建表的命令,统计出数据表的数量,赋值给$total_table,$n为计数器。下面就是foreach遍历被 explode分割的数组,每次循环都去执行SQL语句,同时判断该次执行的语句是否是创建表的,是的话,就显示出数据表的名称,$n++,这个$n就知道是在创建第几张表了。再结合JS控制显示的进度,安装使创建数据的信息超出容器时,就会出现滚动条JS控制滚动条始终在最底部,JS代码是可以在PHP服务端输出的,每执行一次创建数据表的操作,JS便会改变相应控制DOM元素的样式。flush()这个函数是每循环一次刷新出显示的内容,如果不写的话,只有执行完毕之后,页面上才会显示出信息,这样进度条效果便不存在。
所有的SQL语句执行完后,就应该把表单提交过来的数据写进配置文件,这里就是一个读档、开档、替换、开档、写入的过程。可能代码还是多了点,不过仔细去理解一下,还是满充实的。