2018-12-28 18:58:37 +08:00
< ? php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
2021-03-16 10:34:52 +08:00
// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved.
2018-12-28 18:58:37 +08:00
// +----------------------------------------------------------------------
2021-03-16 10:34:52 +08:00
// | Licensed ( https://opensource.org/licenses/mit-license.php )
2018-12-28 18:58:37 +08:00
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\install\controller ;
2021-07-18 23:42:10 +08:00
use think\facade\Db ;
2021-07-25 19:20:42 +08:00
use app\service\SystemService ;
2018-12-28 18:58:37 +08:00
/**
* 安装程序
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 11 - 30
* @ desc description
*/
class Index extends Common
{
2019-01-14 12:27:37 +08:00
// 编码类型
private $charset_type_list ;
2020-09-23 16:03:14 +08:00
// 安装日志上报
private $behavior_obj ;
2024-07-03 22:46:04 +08:00
// 记录管理后台入口文件key
private $admin_run_key = 'cache_install_system_admin_run_key' ;
2018-12-28 18:58:37 +08:00
/**
* 构造方法
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 11 - 30
* @ desc description
*/
public function __construct ()
{
parent :: __construct ();
2019-01-14 12:27:37 +08:00
// 编码类型
$this -> charset_type_list = [
'utf8mb4' => [
'charset' => 'utf8mb4' ,
'collate' => 'utf8mb4_general_ci' ,
'version' => 5.6 ,
],
'utf8' => [
'charset' => 'utf8' ,
'collate' => 'utf8_general_ci' ,
'version' => 5.0 ,
],
];
2020-09-23 16:03:14 +08:00
// 安装日志上报类库
$this -> behavior_obj = new \base\Behavior ();
2018-12-28 18:58:37 +08:00
}
/**
* 是否已安装
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
private function IsInstall ()
{
2019-01-04 17:47:57 +08:00
if ( file_exists ( ROOT . 'config/database.php' ))
2018-12-28 18:58:37 +08:00
{
2022-10-22 20:51:02 +08:00
return DataReturn ( '你已经安装过该系统,重新安装需要先删除 ./config/database.php 文件' , - 1 );
2018-12-28 18:58:37 +08:00
}
2022-10-22 20:51:02 +08:00
return DataReturn ( 'success' , 0 );
2018-12-28 18:58:37 +08:00
}
/**
* 协议
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
public function Index ()
{
2022-10-22 20:51:02 +08:00
$ret = $this -> IsInstall ();
if ( $ret [ 'code' ] != 0 )
{
exit ( $ret [ 'msg' ]);
}
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '协议阅读' ]);
2021-07-18 23:42:10 +08:00
return MyView ();
2018-12-28 18:58:37 +08:00
}
/**
* 检查
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
public function Check ()
{
2022-10-22 20:51:02 +08:00
$ret = $this -> IsInstall ();
if ( $ret [ 'code' ] != 0 )
{
exit ( $ret [ 'msg' ]);
}
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '环境检测' ]);
2021-07-18 23:42:10 +08:00
return MyView ();
2018-12-28 18:58:37 +08:00
}
/**
* 创建数据库
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
public function Create ()
{
2022-10-22 20:51:02 +08:00
$ret = $this -> IsInstall ();
if ( $ret [ 'code' ] != 0 )
{
exit ( $ret [ 'msg' ]);
}
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '数据信息填写' ]);
2019-01-14 12:27:37 +08:00
2021-07-18 23:42:10 +08:00
MyViewAssign ( 'charset_type_list' , $this -> charset_type_list );
return MyView ();
2018-12-28 18:58:37 +08:00
}
/**
* 完成
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
public function Successful ()
{
2024-07-03 22:46:04 +08:00
// 安装验证
2021-07-25 19:20:42 +08:00
SystemService :: SystemInstallCheck ();
2024-07-03 22:46:04 +08:00
// 管理入口地址
MyViewAssign ( 'admin_run' , MySession ( $this -> admin_run_key ));
2021-07-18 23:42:10 +08:00
return MyView ();
2018-12-28 18:58:37 +08:00
}
/**
2021-07-25 19:20:42 +08:00
* 确认、安装应用模块创建数据库配置文件
2018-12-28 18:58:37 +08:00
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
2021-07-25 19:20:42 +08:00
public function Confirm ()
2018-12-28 18:58:37 +08:00
{
2019-01-04 17:47:57 +08:00
// 是否ajax
if ( ! IS_AJAX )
{
2021-07-25 19:20:42 +08:00
MyViewAssign ( 'msg' , '非法访问' );
return MyView ( 'public/error' );
2019-01-04 17:47:57 +08:00
}
2018-12-28 18:58:37 +08:00
// 参数
2023-11-08 15:43:08 +08:00
$params = $this -> RequestParams ();
2018-12-28 18:58:37 +08:00
$ret = $this -> ParamsCheck ( $params );
if ( $ret [ 'code' ] != 0 )
{
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '参数校验[' . $ret [ 'msg' ] . ']' ]);
2018-12-28 18:58:37 +08:00
return $ret ;
}
// 配置文件校验
2022-10-22 20:51:02 +08:00
$ret = $this -> IsInstall ();
if ( $ret [ 'code' ] != 0 )
2018-12-28 18:58:37 +08:00
{
2022-10-22 20:51:02 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => 'Confirm():' . $ret [ 'msg' ]]);
return $ret ;
2018-12-28 18:58:37 +08:00
}
2021-07-25 19:20:42 +08:00
// 安装应用数据库配置文件生成
return $this -> CreateDbConfig ( APP_PATH . 'install/config' , $params );
}
/**
* 安装
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
*/
public function Add ()
{
// 是否ajax
if ( ! IS_AJAX )
{
MyViewAssign ( 'msg' , '非法访问' );
return MyView ( 'public/error' );
}
2022-10-22 20:51:02 +08:00
// 配置文件校验
$ret = $this -> IsInstall ();
if ( $ret [ 'code' ] != 0 )
{
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => 'Add():' . $ret [ 'msg' ]]);
return $ret ;
}
2018-12-28 18:58:37 +08:00
// 开始安装
2023-11-08 15:43:08 +08:00
$params = $this -> RequestParams ();
2018-12-28 18:58:37 +08:00
$db = $this -> DbObj ( $params );
if ( ! is_object ( $db ))
{
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '数据库连接失败' ]);
2018-12-28 18:58:37 +08:00
return DataReturn ( '数据库连接失败' , - 1 );
}
// mysql版本
2019-01-14 12:27:37 +08:00
$ret = $this -> IsVersion ( $db , $params [ 'DB_CHARSET' ]);
2018-12-28 18:58:37 +08:00
if ( $ret [ 'code' ] != 0 )
{
return $ret ;
}
// 创建数据表
$ret = $this -> CreateTable ( $db , $params );
if ( $ret [ 'code' ] != 0 )
{
return $ret ;
}
2020-09-25 23:37:04 +08:00
// 生成数据库配置文件
2021-07-25 19:20:42 +08:00
$ret = $this -> CreateDbConfig ( ROOT . 'config' , $params );
if ( $ret [ 'code' ] == 0 )
{
$ret [ 'msg' ] = '安装成功' ;
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '安装成功' ]);
}
2024-07-03 22:46:04 +08:00
// 管理入口文件处理
return $this -> AdminRunFileHandle ();
2018-12-28 18:58:37 +08:00
}
2023-11-08 15:43:08 +08:00
/**
* 请求参数
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2023 - 09 - 23
* @ desc description
*/
public function RequestParams ()
{
$params = input ( 'post.' );
if ( ! empty ( $params ) && is_array ( $params ))
{
// 需要去除的特殊字符
$search = [ '<?php' , '<?' , '?>' , '\'' , '"' , '"' , '\\' , 'eval(' , '&' , '<' , '>' ];
foreach ( $params as & $v )
{
// 去除的特殊字符
if ( ! is_array ( $v ))
{
$v = str_replace ( $search , '' , $v );
}
}
}
return $params ;
}
2024-07-03 22:46:04 +08:00
/**
* 管理入口文件处理
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
* @ param [ array ] $params [ 输入参数 ]
*/
private function AdminRunFileHandle ( $params = [])
{
// 处理文件名称修改
$admin_filename_new = 'admin' . strtolower ( RandomString ( 6 )) . '.php' ;
$arr = [ ROOT , ROOT . 'public' . DS ];
foreach ( $arr as $v )
{
if ( file_exists ( $v . 'admin.php' ))
{
\base\FileUtil :: MoveFile ( $v . 'admin.php' , $v . $admin_filename_new );
}
}
// 记录管理地址
2024-10-21 10:51:14 +08:00
MySession ( $this -> admin_run_key , __MY_URL__ . $admin_filename_new . '?s=index/index.html' );
2024-07-03 22:46:04 +08:00
return DataReturn ( MyLang ( 'operate_success' ), 0 );
}
2018-12-28 18:58:37 +08:00
/**
* 生成配置文件
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
2021-07-25 19:20:42 +08:00
* @ param [ string ] $dir [ 目录地址 ]
* @ param [ array ] $params [ 输入参数 ]
2018-12-28 18:58:37 +08:00
*/
2021-07-25 19:20:42 +08:00
private function CreateDbConfig ( $dir , $params = [])
2018-12-28 18:58:37 +08:00
{
$db_str =<<< php
< ? php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
2021-03-16 10:34:52 +08:00
// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved.
2018-12-28 18:58:37 +08:00
// +----------------------------------------------------------------------
2021-03-16 10:34:52 +08:00
// | Licensed ( https://opensource.org/licenses/mit-license.php )
2018-12-28 18:58:37 +08:00
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | 数据库配置
// +----------------------------------------------------------------------
return [
2021-07-18 23:42:10 +08:00
// 默认使用的数据库连接配置
'default' => 'mysql' ,
// 自定义时间查询规则
'time_query_rule' => [],
2018-12-28 18:58:37 +08:00
// 自动写入时间戳字段
2021-07-18 23:42:10 +08:00
// true为自动识别类型 false关闭
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
'auto_timestamp' => true ,
2018-12-28 18:58:37 +08:00
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s' ,
2021-07-18 23:42:10 +08:00
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => '{$params[' DB_TYPE ']}' ,
// 服务器地址
'hostname' => '{$params[' DB_HOST ']}' ,
// 数据库名
'database' => '{$params[' DB_NAME ']}' ,
// 用户名
'username' => '{$params[' DB_USER ']}' ,
// 密码
'password' => '{$params[' DB_PWD ']}' ,
// 端口
'hostport' => '{$params[' DB_PORT ']}' ,
// 数据库连接参数
'params' => [
\PDO :: ATTR_CASE => \PDO :: CASE_LOWER ,
\PDO :: ATTR_EMULATE_PREPARES => true ,
],
2021-08-25 11:00:18 +08:00
// 数据库编码默认采用utf8mb4
2021-07-18 23:42:10 +08:00
'charset' => '{$params[' DB_CHARSET ']}' ,
// 数据库表前缀
'prefix' => '{$params[' DB_PREFIX ']}' ,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0 ,
// 数据库读写是否分离 主从式有效
'rw_separate' => false ,
// 读写分离后 主服务器数量
'master_num' => 1 ,
// 指定从服务器序号
'slave_no' => '' ,
// 是否严格检查字段是否存在
'fields_strict' => true ,
// 是否需要断线重连
'break_reconnect' => false ,
// 监听SQL
2022-10-28 17:08:13 +08:00
'trigger_sql' => false ,
2021-07-18 23:42:10 +08:00
// 开启字段缓存
2021-08-29 14:20:21 +08:00
'fields_cache' => false ,
2021-07-18 23:42:10 +08:00
]
]
2018-12-28 18:58:37 +08:00
];
?>
php ;
2021-07-25 19:20:42 +08:00
if ( @ file_put_contents ( $dir . '/database.php' , $db_str ) === false )
2018-12-28 18:58:37 +08:00
{
2021-07-25 19:20:42 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '配置文件创建失败[' . $dir . ']' ]);
2018-12-28 18:58:37 +08:00
return DataReturn ( '配置文件创建失败' , - 1 );
}
2023-02-04 16:47:48 +08:00
return DataReturn ( MyLang ( 'operate_success' ), 0 );
2018-12-28 18:58:37 +08:00
}
/**
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
* @ param [ object ] $db [ db对象 ]
* @ param [ array ] $params [ 输入参数 ]
*/
private function CreateTable ( $db , $params )
{
2019-01-04 17:47:57 +08:00
if ( ! file_exists ( ROOT . 'config/shopxo.sql' ))
2018-12-28 18:58:37 +08:00
{
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '数据库sql文件不存在' ]);
2018-12-28 18:58:37 +08:00
return DataReturn ( '数据库sql文件不存在' , - 1 );
}
// sql文件
2019-01-04 17:47:57 +08:00
$sql = file_get_contents ( ROOT . 'config/shopxo.sql' );
2018-12-28 18:58:37 +08:00
2021-04-07 14:17:35 +08:00
// 替换表前缀
if ( $params [ 'DB_PREFIX' ] != 'sxo_' )
{
$sql = str_replace ( " `sxo_ " , " ` { $params [ 'DB_PREFIX' ] } " , $sql );
}
2018-12-28 18:58:37 +08:00
2021-12-26 13:16:14 +08:00
// 编码替换处理
2019-01-14 12:27:37 +08:00
$charset = $this -> charset_type_list [ $params [ 'DB_CHARSET' ]];
2021-12-26 13:16:14 +08:00
$charset_old = $this -> charset_type_list [( $charset [ 'charset' ] == 'utf8' ) ? 'utf8mb4' : 'utf8' ];
// 编码替换操作
$sql = str_replace ( " SET NAMES { $charset_old [ 'charset' ] } ; " , " SET NAMES { $charset [ 'charset' ] } ; " , $sql );
$sql = str_replace ( " SET { $charset_old [ 'charset' ] } " , " SET { $charset [ 'charset' ] } " , $sql );
$sql = str_replace ( " COLLATE { $charset_old [ 'collate' ] } " , " COLLATE { $charset [ 'collate' ] } " , $sql );
$sql = str_replace ([ " SET = { $charset_old [ 'charset' ] } " , " SET= { $charset_old [ 'charset' ] } " ], " SET= { $charset [ 'charset' ] } " , $sql );
$sql = str_replace ([ " COLLATE = { $charset_old [ 'collate' ] } " , " COLLATE= { $charset_old [ 'collate' ] } " ], " COLLATE= { $charset [ 'collate' ] } " , $sql );
$sql = str_replace ([ " CHARSET = { $charset_old [ 'charset' ] } " , " CHARSET= { $charset_old [ 'charset' ] } " ], " CHARSET= { $charset [ 'charset' ] } " , $sql );
$sql = str_replace ( $charset_old [ 'collate' ], $charset [ 'collate' ], $sql );
2019-01-14 12:27:37 +08:00
2018-12-28 18:58:37 +08:00
// 转为数组
$sql_all = preg_split ( " /;[ \r \n ]+/ " , $sql );
$success = 0 ;
$failure = 0 ;
foreach ( $sql_all as $v )
{
if ( ! empty ( $v ))
{
2018-12-29 13:13:09 +08:00
if ( $db -> execute ( $v ) !== false )
2018-12-28 18:58:37 +08:00
{
2018-12-29 13:13:09 +08:00
$success ++ ;
2018-12-28 18:58:37 +08:00
} else {
2018-12-29 13:13:09 +08:00
$failure ++ ;
}
2018-12-28 18:58:37 +08:00
}
}
$result = [
'success' => $success ,
'failure' => $failure ,
];
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => 'sql运行 成功[' . $success . ']条, 失败[' . $failure . ']条' ]);
2018-12-28 18:58:37 +08:00
if ( $failure > 0 )
{
return DataReturn ( 'sql运行失败[' . $failure . ']条' , - 1 );
}
2023-09-17 22:54:33 +08:00
// 更新管理员账号密码
$login_salt = GetNumberCode ( 6 );
$login_pwd = LoginPwdEncryption ( $params [ 'ADMIN_PWD' ], $login_salt );
$db -> execute ( 'UPDATE `' . $params [ 'DB_PREFIX' ] . 'admin` SET `username`="' . $params [ 'ADMIN_USERNAME' ] . '", login_pwd="' . $login_pwd . '", `login_salt`="' . $login_salt . '" WHERE `id`=1' );
2023-08-29 13:13:32 +08:00
// 更新加密串
$db -> execute ( 'UPDATE `' . $params [ 'DB_PREFIX' ] . 'config` SET `value`="' . md5 ( time () . rand ( 100 , 99999 )) . '" WHERE `only_tag`="common_data_encryption_secret"' );
2018-12-28 18:58:37 +08:00
return DataReturn ( 'success' , 0 , $result );
}
/**
* 数据库版本校验
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
2019-01-14 12:27:37 +08:00
* @ param [ object ] $db [ db对象 ]
* @ param [ string ] $db_charset [ 数据库编码 ]
2018-12-28 18:58:37 +08:00
*/
2019-01-14 12:27:37 +08:00
private function IsVersion ( $db , $db_charset )
2018-12-28 18:58:37 +08:00
{
2021-07-25 19:20:42 +08:00
$data = $db -> query ( 'SELECT VERSION() AS `version`' );
2018-12-28 18:58:37 +08:00
if ( empty ( $data [ 0 ][ 'version' ]))
{
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => '查询数据库版本失败' ]);
2018-12-28 18:58:37 +08:00
return DataReturn ( '查询数据库版本失败' , - 1 );
} else {
2019-01-14 12:27:37 +08:00
$mysql_version = str_replace ( '-log' , '' , $data [ 0 ][ 'version' ]);
if ( $mysql_version < $this -> charset_type_list [ $db_charset ][ 'version' ])
2018-12-28 18:58:37 +08:00
{
2019-01-14 12:27:37 +08:00
$msg = '数据库版本过低、需要>=' . $this -> charset_type_list [ $db_charset ][ 'version' ] . '、当前' . $mysql_version ;
2020-09-23 16:03:14 +08:00
$this -> behavior_obj -> ReportInstallLog ([ 'msg' => $msg , 'mysql_version' => $mysql_version ]);
2019-01-14 12:27:37 +08:00
return DataReturn ( $msg , - 1 );
2018-12-28 18:58:37 +08:00
}
}
return DataReturn ( 'success' , 0 );
}
/**
* 获取数据库操作对象
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
* @ param array $params [ 输入参数 ]
* @ param string $db_name [ 数据库名称 ]
*/
private function DbObj ( $params = [], $db_name = '' )
{
2021-07-25 19:20:42 +08:00
return Db :: connect ( 'mysql' );
2018-12-28 18:58:37 +08:00
}
/**
* 参数校验
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2018 - 12 - 28
* @ desc description
* @ param [ array ] $params [ 输入参数 ]
*/
private function ParamsCheck ( $params = [])
{
// 请求类型
$p = [
2021-09-07 13:40:11 +08:00
[
'checked_type' => 'empty' ,
'key_name' => 'DB_TYPE' ,
'error_msg' => '请选择数据库类型' ,
],
2019-01-14 12:27:37 +08:00
[
'checked_type' => 'in' ,
'key_name' => 'DB_CHARSET' ,
'checked_data' => array_column ( $this -> charset_type_list , 'charset' ),
'error_msg' => '请选择数据编码' ,
],
2018-12-28 18:58:37 +08:00
[
'checked_type' => 'empty' ,
'key_name' => 'DB_HOST' ,
'error_msg' => '请填写数据库服务器地址' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'DB_PORT' ,
'error_msg' => '请填写数据库端口' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'DB_NAME' ,
'error_msg' => '请填写数据库名' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'DB_USER' ,
'error_msg' => '请填写数据库用户名' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'DB_PWD' ,
'error_msg' => '请填写数据库密码' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'DB_PREFIX' ,
'error_msg' => '请填写数据表前缀' ,
],
2023-09-17 22:54:33 +08:00
[
'checked_type' => 'empty' ,
'key_name' => 'ADMIN_USERNAME' ,
'error_msg' => '请填写管理员账号' ,
],
[
'checked_type' => 'empty' ,
'key_name' => 'ADMIN_PWD' ,
'error_msg' => '请填写管理员密码' ,
],
2018-12-28 18:58:37 +08:00
];
$ret = ParamsChecked ( $params , $p );
if ( $ret !== true )
{
return DataReturn ( $ret , - 1 );
}
return DataReturn ( 'success' , 0 );
}
}
?>