<?php
//  ---------------------------------------------------------------------------------
//    _____   _             _                   _   _____
//   |  __ \ | |           | |    /\           (_) |  __ \
//   | |__) || |__    __ _ | |   /  \    _ __   _  | |__) |_ __  ___
//   |  ___/ | '_ \  / _` || |  / /\ \  | '_ \ | | |  ___/| '__|/ _ \
//   | |     | | | || (_| || | / ____ \ | |_) || | | |    | |  | (_) |
//   |_|     |_| |_| \__,_||_|/_/    \_\| .__/ |_| |_|    |_|   \___/
//                                      | |
//                                      |_|
//   PhalApi Pro 专业版
//   广州果创网络科技有限公司
//
//  ---------------------------------------------------------------------------------
//
//   一、协议的许可和权利
//    1. 您可以在完全遵守本协议的基础上，将本软件应用于商业用途；
//    2. 您可以在协议规定的约束和限制范围内修改本产品源代码或界面风格以适应您的要求；
//    3. 您拥有使用本产品中的全部内容资料、商品信息及其他信息的所有权，并独立承担与其内容相关的
//       法律义务；
//    4. 获得商业授权之后，您可以将本软件应用于商业用途，自授权时刻起，在技术支持期限内拥有通过
//       指定的方式获得指定范围内的技术支持服务；
//
//   二、协议的约束和限制
//    1. 未获商业授权之前，禁止将本软件用于商业用途（包括但不限于企业法人经营的产品、经营性产品
//       以及以盈利为目的或实现盈利产品）；
//    2. 未获商业授权之前，禁止在本产品的整体或在任何部分基础上发展任何派生版本、修改版本或第三
//       方版本用于重新开发；
//    3. 如果您未能遵守本协议的条款，您的授权将被终止，所被许可的权利将被收回并承担相应法律责任；
//
//   三、有限担保和免责声明
//    1. 本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的；
//    2. 用户出于自愿而使用本软件，您必须了解使用本软件的风险，在尚未获得商业授权之前，我们不承
//       诺提供任何形式的技术支持、使用担保，也不承担任何因使用本软件而产生问题的相关责任；
//    3. 广州果创网络科技有限公司不对使用本产品构建的商城中的内容信息承担责任，但在不侵犯用户隐
//       私信息的前提下，保留以任何方式获取用户信息及商品信息的权利；
//
//   有关本产品最终用户授权协议、商业授权与技术服务的详细内容，均由广州果创网络科技有限公司独家
//   提供。广州果创网络科技有限公司拥有在不事先通知的情况下，修改授权协议的权力，修改后的协议对
//   改变之日起的新授权用户生效。电子文本形式的授权协议如同双方书面签署的协议一样，具有完全的和
//   等同的法律效力。您一旦开始修改、安装或使用本产品，即被视为完全理解并接受本协议的各项条款，
//   在享有上述条款授予的权力的同时，受到相关的约束和限制。协议许可范围以外的行为，将直接违反本
//   授权协议并构成侵权，我们有权随时终止授权，责令停止损害，并保留追究相关责任的权力。
//
//  ---------------------------------------------------------------------------------

error_reporting(E_ALL);
ini_set('display_errors', 'On'); 

define('PHALAPI_INSTALL', TRUE);
define('D_S', DIRECTORY_SEPARATOR);

$step = isset($_GET['step']) ? intval($_GET['step']) : 0;

$runtimePath = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'runtime'));
if (file_exists($runtimePath . D_S . '_install.lock')) {
    $error = '项目已安装，请不要重复安装。<br/>成功安装 后，建议手动删除 ./public/install目录。<br/>如果需要安装，请手动删除./runtime/_install.lock文件。';
    include dirname(__FILE__) . D_S . '_error.php';
    exit(0);
}

switch ($step) {
    //第一步：环境检测
case 1:
    //-1：必须但不支持 0：可选但不支持 1：完美支持
    $checkList = array(
        'php'       => array('name' => 'PHP 版本', 'status' => -1, 'tip' => '建议使用PHP 5.3.3及以上版本，推荐使用PHP 7'),
        'opcache'       => array('name' => 'Opcache', 'status' => -1, 'tip' => '开启opcache后，将无法生成在线接口文档，需要设置opcache.enable=0关闭opcache'),
        'pdo'       => array('name' => '数据库模块', 'status' => -1, 'tip' => '建议使用PDO扩展，否则NotORM无法使用PDO进行数据库操作'),
        //'memcache'  => array('name' => 'Memcache扩展', 'status' => 0, 'tip' => '无此扩展时，不能使用Memcache缓存'),
        //'mcrypt'    => array('name' => 'Mcrypt扩展', 'status' => 0, 'tip' => '无此扩展时，不能使用mcrypt进行加密处理'),
        'config'   => array('name' => '配置目录权限', 'status' => -1, 'tip' => '配置文件目录缺少写入权限，无法写入配置，将会导致安装失败，需要手动添加写入权限。'),
        'runtime'   => array('name' => '运行时目录权限', 'status' => -1, 'tip' => '运行时目录缺少写入权限，将不能写入日记和进行文件缓存，需要手动添加写入权限。'),
        'uploads'   => array('name' => '文件上传目录权限', 'status' => -1, 'tip' => '文件上传目录缺少写入权限，将不能上传文件，需要手动添加写入权限。'),
    );

    if (version_compare(PHP_VERSION, '5.3.3', '>=')) {
        $checkList['php']['status'] = 1;
    }
    if (class_exists('PDO', false) && extension_loaded('PDO')) {
        $checkList['pdo']['status'] = 1;
    }
    
    if (ini_get('opcache.enable') === false || ini_get('opcache.enable') == '0') {
        $checkList['opcache']['status'] = 1;
    }
//     if (class_exists('Memcache', false) && extension_loaded('memcache')) {
//         $checkList['memcache']['status'] = 1;
//     }
//     if (extension_loaded('mcrypt')) {
//         $checkList['mcrypt']['status'] = 1;
//     }
    $runtimePath = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'runtime'));
    $runtimePath = file_exists($runtimePath) ? realpath($runtimePath) : $runtimePath;
    $checkList['runtime']['tip'] = $runtimePath . '<br>' . $checkList['runtime']['tip'];
    if (is_writeable($runtimePath)) {
        $checkList['runtime']['status'] =  1;
    }
    
    $configPath = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'config'));
    $configPath = file_exists($configPath) ? realpath($configPath) : $configPath;
    $checkList['config']['tip'] = $configPath . '<br>' . $checkList['config']['tip'];
    if (is_writeable($configPath)) {
        $checkList['config']['status'] =  1;
    }
    
    $publicPath = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'public', 'uploads'));
    $publicPath = file_exists($publicPath) ? realpath($publicPath) : $publicPath;
    $checkList['uploads']['tip'] = $publicPath . '<br>' . $checkList['uploads']['tip'];
    if (is_writable($publicPath)) {
        $checkList['uploads']['status'] =  1;
    }

    include dirname(__FILE__) . D_S . '_step1.php';
    break;
    //第2步：系统配置
case 2:
    include dirname(__FILE__) . D_S . '_step2.php';
    break;
    //第3步：接口请求
case 3:
    if (empty($_POST['doSubmit']) || empty($_POST)) {
        header('Location: ./?step=1');
        exit(0);
    }

    //数据库配置文件
    $search = array(
        '{project}',
        '{host}',
        '{name}',
        '{user}',
        '{password}',
        '{port}',
        '{charset}',
        '{prefix}',
    );
    $replace = array(
        'phalapi_pro',
        $_POST['host'],
        $_POST['name'],
        $_POST['user'],
        $_POST['password'],
        $_POST['port'],
        'utf8mb4', // $_POST['charset'],
        $_POST['prefix'],
    );
    $configDbsContent = str_replace($search, $replace, getConfigDbsTpl());
    file_put_contents(
        dirname(__FILE__) . implode(D_S, array('', '..', '..', 'config', 'dbs.php')),
        $configDbsContent
    );
    
    // 应用配置
    $appCfgFile = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'config', 'app.php'));
    $configAppContent = str_replace(
        array('*#FD2F9DM~E*', '9DfnseJ%sD#', '果果云'), 
        array(createRandStr(12), createRandStr(12), !empty($_POST['project_name']) ? str_replace("'", '', $_POST['project_name']) : '果果云'), 
        file_get_contents($appCfgFile)
    );
    @file_put_contents($appCfgFile, $configAppContent);

    // 创建数据库
    $sql = "CREATE DATABASE IF NOT EXISTS {$_POST['name']} DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;";
    sqlExcute($_POST['host'] . ':' . $_POST['port'], $_POST['user'], $_POST['password'], $sql);
    
    // 导入数据库
    $sqlFile = dirname(__FILE__) . implode(D_S, array('', '..', '..', 'data', 'phalapi_pro.sql'));
    require_once dirname(__FILE__) . implode(D_S, array('', '..', '..', 'public', 'init.php'));
    $sqlContent = str_replace('`pp_', '`' . $_POST['prefix'], file_get_contents($sqlFile));
    $sqlArr = explode(";\n", str_replace(";\r\n", ";\n", $sqlContent)); // 兼容windows系统的换行

    // 开启调试，避免安装过程中连接不上，可以相撞看原因
    \PhalApi\DI()->debug = true;

    foreach ($sqlArr as $sql) {
        $sql = trim($sql);
        if (empty($sqlArr)) {
            continue;
        }
        try {
            \PhalApi\DI()->notorm->demo->executeSql($sql);
        } catch (Exception $ex) {
            $error = $ex->getTraceAsString();
            $error = $ex->getMessage() . '<hr/>' . str_replace("\n", '<br />', $error);
            include dirname(__FILE__) . D_S . '_error.php';
            die();
        }
    }

    // 创建管理员
    $userDomain = new \Base\Domain\User();
    $userDomain->register($_POST['admin_user'], $_POST['admin_pass'], '', '超级管理员', '', 0, '', \Base\Domain\UserType::MEMBER_LEVEL_SUPER_ADMIN);
    
    touch($runtimePath . D_S . '_install.lock');

    //请求链接
    $apiUrl = 'http://' . $_SERVER['HTTP_HOST'] . '/docs.php';
    include dirname(__FILE__) . D_S . '_step3.php';
    break;
default:
    include dirname(__FILE__) . D_S . '_start.php';
}

function createRandStr($len, $chars = null) {
    if (!$chars) {
        $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    }
    
    return substr(str_shuffle(str_repeat($chars, rand(5, 8))), 0, $len);
}

function getConfigDbsTpl() {
    $configDbs = <<<EOT
<?php
/**
 * 分库分表的自定义数据库路由配置
 * 
 * @license     http://www.phalapi.net/license GPL 协议
 * @link        http://www.phalapi.net/
 * @author: dogstar <chanzonghuang@gmail.com> 2015-02-09
 */

return array(
    /**
     * DB数据库服务器集群
     */
    'servers' => array(
        'db_master' => array(                   //服务器标记
            'host'      => '{host}',               //数据库域名
            'name'      => '{name}',               //数据库名字
            'user'      => '{user}',               //数据库用户名
            'password'  => '{password}',           //数据库密码
            'port'      => '{port}',               //数据库端口
            'charset'   => '{charset}',            //数据库字符集
            'pdo_attr_string'   => false,           // 数据库查询结果统一使用字符串，true是，false否
            'driver_options' => array(              // PDO初始化时的连接选项配置
                // 若需要更多配置，请参考官方文档：https://www.php.net/manual/zh/pdo.constants.php
            ),
        ),
    ),

    /**
     * 自定义路由表
     */
    'tables' => array(
        //通用路由
        '__default__' => array(
            'prefix' => '{prefix}',
            'key' => 'id',
            'map' => array(
                array('db' => 'db_master'),
            ),
        ),

        /**
        'demo' => array(                                                //表名
            'prefix' => '',                                     //表名前缀
            'key' => 'id',                                              //表主键名
            'map' => array(                                             //表路由配置
                array('db' => 'db_master'),                               //单表配置：array('db' => 服务器标记)
                array('start' => 0, 'end' => 2, 'db' => 'db_master'),     //分表配置：array('start' => 开始下标, 'end' => 结束下标, 'db' => 服务器标记)
            ),
        ),
         */
    ),
);

EOT;

    return $configDbs;
}


function sqlExcute($servername, $username, $password, $sql)
{
    // 创建连接
    $conn = mysqli_connect($servername, $username, $password);
    // 检测连接
    if ($conn) {
        // 执行sql
        if ($conn->query($sql) === TRUE) {
            return true;
        }
        $conn->close();
        // die("Connection failed: " . mysqli_connect_error());
    }
    return false;
}
