ThinkPHP3.2应用部署

Published on 2016 - 11 - 28

PATH_INFO支持

如果发生在本地测试正常,但是一旦部署到服务器环境后会发生只能访问首页的情况,很有可能是你的服务器或者空间不支持PATH_INFO所致。

系统内置提供了对PATH_INFO的兼容判断处理,但是不能确保在所有的环境下面都可以支持。如果你确认你的空间不支持PATH_INFO的URL方式的话,有下面几种方式可以处理:

修改URL_PATHINFO_FETCH配置参数新版内置了通过对ORIG_PATH_INFO, REDIRECT_PATH_INFO, REDIRECT_URL三个系统$_SERVER变量的判断处理来兼容读取$_SERVER['PATH_INFO'],如果你的主机环境有更特殊的设置,可以修改URL_PATHINFO_FETCH参数,改成你的环境配置对应的PATH_INFO的系统变量兼容获取名称,例如:

'URL_PATHINFO_FETCH' => 'ORIG_PATH_INFO,REDIRECT_URL,其他参数…'

如果你的环境没有任何对应的系统变量,那么可以封装一个获取方法,例如:

function get_path_info(){
     // 根据你的环境兼容获取PATH_INFO 具体代码略
     return $path; // 直接返回获取到的PATH_INFO信息
}

然后我们修改下URL_PATHINFO_FETCH参数的配置值,改为:

'URL_PATHINFO_FETCH'     =>   ':get_path_info'

配置后,系统会自动读取get_path_info方法来获取$_SERVER['PATH_INFO']的值。

配置你的WEB服务器重写规则模拟PATH_INFO实现如果你有服务器或者空间的配置权限,可以考虑通过配置URL重写规则来模拟实现。

采用兼容URL模式运行这是最坏的方法,配置你的URL模式为3(表示兼容URL模式) 然后在需要生成URL的地方采用U方法动态生成即可。

URL重写

可以通过URL重写隐藏应用的入口文件index.php,下面是相关服务器的配置参考:

Apache

  1. httpd.conf配置文件中加载了mod_rewrite.so模块
  2. AllowOverride None 将None改为 All
  3. 把下面的内容保存为.htaccess文件放到应用入口文件的同级目录下
<IfModule mod_rewrite.c>
 RewriteEngine on
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

IIS

如果你的服务器环境支持ISAPI_Rewrite的话,可以配置httpd.ini文件,添加下面的内容:

RewriteRule (.*)$ /index\.php\?s=$1 [I]

在IIS的高版本下面可以配置web.Config,在中间添加rewrite节点:

<rewrite>
 <rules>
 <rule name="OrgPage" stopProcessing="true">
 <match url="^(.*)$" />
 <conditions logicalGrouping="MatchAll">
 <add input="{HTTP_HOST}" pattern="^(.*)$" />
 <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
 <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
 </conditions>
 <action type="Rewrite" url="index.php/{R:1}" />
 </rule>
 </rules>
 </rewrite>

Nginx

在Nginx低版本中,是不支持PATHINFO的,但是可以通过在Nginx.conf中配置转发规则实现:

  location / { // …..省略部分代码
   if (!-e $request_filename) {
   rewrite  ^(.*)$  /index.php?s=$1  last;
   break;
    }
 }

其实内部是转发到了ThinkPHP提供的兼容模式的URL,利用这种方式,可以解决其他不支持PATHINFO的WEB服务器环境。

如果你的ThinkPHP安装在二级目录,Nginx的伪静态方法设置如下,其中youdomain是所在的目录名称。

location /youdomain/ {
    if (!-e $request_filename){
        rewrite  ^/youdomain/(.*)$  /youdomain/index.php?s=$1  last;
    }
}

原来的访问URL:

http://serverName/index.php/模块/控制器/操作/[参数名/参数值...]

设置后,我们可以采用下面的方式访问:

http://serverName/模块/控制器/操作/[参数名/参数值...]

默认情况下,URL地址中的模块不能省略,如果你需要简化某个模块的URL访问地址,可以通过设置模块列表和默认模块或者采用子域名部署到模块的方式解决。

模块部署

3.2对模块的访问是自动判断的,所以通常情况下无需配置模块列表即可访问,在部署模块的时候,默认情况下都是基于类似于子目录的URL方式来访问模块的,例如:

http://serverName/Home/New/index //访问Home模块 
http://serverName/Admin/Config/index //访问Admin模块
http://serverName/User/Member/index //访问User模块

允许模块列表

如果直接访问:http://serverName/New/index 会报错,不过通过下面的设置可以把Home模块的访问URL地址简化:

// 允许访问的模块列表
'MODULE_ALLOW_LIST'    =>    array('Home','Admin','User');
'DEFAULT_MODULE'       =>    'Home',  // 默认模块

这个时候再次访问 http://serverName/New/index 就不会报错了,并且实际访问的就是Home模块。默认情况下,MODULE_ALLOW_LIST 为空,表示允许任何模块的访问,不过最终是否允许访问还受 MODULE_DENY_LIST 参数的影响。

域名绑定的模块不受MODULE_ALLOW_LIST的影响

禁止模块访问

如果你的应用有很多的模块,你只是想禁止访问个别模块的话,可以配置禁止访问的模块列表(用于被其他模块调用或者不开放访问),默认配置中是禁止访问Common模块和Runtime模块(Runtime目录是默认的运行时目录),我们可以增加其他的禁止访问模块列表:

// 设置禁止访问的模块列表
 'MODULE_DENY_LIST'      =>  array('Common','Runtime','User'),

这个时候,我们再访问 http://serverName/User/Member/index 的话,就会报错。

域名绑定的模块同样不受MODULE_DENY_LIST影响

模块映射

如果不希望用户直接访问某个模块,可以设置模块映射(对后台的保护会比较实用)。

'URL_MODULE_MAP'    =>    array('test'=>'admin'),

注意:设置了模块映射后,原来的Admin模块将不能访问,只能访问test模块。

我们访问 http://serverName/Admin将会报模块不存在的错误,而 http://serverName/test 则可以正常访问Admin模块。

如果你同时还设置了MODULE_ALLOW_LIST参数的话,必须将允许模块列表中的原来的模块改成映射后的模块名,例如:

'MODULE_ALLOW_LIST'    =>    array('Home','Test','User'),
'DEFAULT_MODULE'       =>    'Home',
'URL_MODULE_MAP'       =>    array('test'=>'admin'),

模块映射的模块必须使用小写定义

域名部署

ThinkPHP支持模块(甚至可以包含控制器)的完整域名、子域名和IP部署功能,让你的模块变得更加灵活,模块绑定到域名或者IP后,URL地址中的模块名称就可以省略了,所以还可以起到简化URL的作用。

开启域名部署

无论是子域名还是IP部署,首先要在应用配置文件中开启APP_SUB_DOMAIN_DEPLOY,这是前提,然后配置域名部署规则APP_SUB_DOMAIN_RULES。

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名或者IP配置
'APP_SUB_DOMAIN_RULES'    =>    array( 
    /* 域名部署配置 
    *格式1: '子域名或泛域名或IP'=> '模块名[/控制器名]'; 
    *格式2: '子域名或泛域名或IP'=> array('模块名[/控制器名]','var1=a&var2=b&var3=*'); 
    */ 
)

域名部署的定义格式2和1的区别在于格式2可以隐式传入额外的参数。

域名或者IP部署到模块并不需要设置模块访问列表。

完整域名部署

可以在域名规则中直接定义完整的域名,例如:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    'admin.domain1.com'  => 'Admin',  // admin.domain1.com域名指向Admin模块
    'test.domain2.com'   => 'Test',  // test.domain2.com域名指向Test模块
),

在域名部署之前的访问地址: http://www.domain.com/Admin/Index/index 和 http://www.domain.com/Test/Index/index

域名部署后的访问地址变成: http://admin.domain1.com/Index/index 和 http://test.domain2.com/Index/index

子域名部署

子域名部署包括任意级子域名的支持,在你的应用配置文件中增加如下配置参数:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    'admin'        => 'Admin',  // admin子域名指向Admin模块
    'test'         => 'Test',  // test子域名指向Test模块
),

部署之前的访问地址:http://www.domain.com/Admin/Index/index

部署后的访问地址变成: http://admin.domain.com/Index/index

如果你的部署域名后缀是二级后缀,例如 com.cn 、net.cn 或者 org.cn 之类的话,为了让系统更好的识别你的子域名,需要配置APP_DOMAIN_SUFFIX如下:

'APP_DOMAIN_SUFFIX'=>'com.cn'

APP_DOMAIN_SUFFIX参数不支持设置多个后缀,如果你是一级域名后缀的话则该参数可以无需任何设置。

传入参数

子域名部署的时候,可以传入隐式的参数,例如:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    'admin'        => array('Admin','var1=1&var2=2'),  // admin子域名指向Admin模块
),

访问 http://admin.domain.com/Index/index 的同时会传入 $_GET['var1'] = 1 和 $_GET['var2'] = 2 两个参数。

控制器绑定

子域名部署还可以支持绑定某个控制器,例如:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    'test.admin'   => 'Admin/Test',  // test.admin子域名指向Admin模块的Test控制器
),

部署之前的访问地址: http://www.domain.com/Admin/Test/index

部署后的访问地址: http://test.admin.domain.com/index

泛域名部署

如果要部署某个模块到泛域名支持,可以使用:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    'admin'    =>    'Admin',  // admin域名指向Admin模块
    '*'        =>    array('Test','var1=1&var2=*'), // 二级泛域名指向Test模块
    '*.user'   =>    array('User','status=1&name=*'),  // 三级泛域名指向User模块
),

配置后,我们可以访问:

http://hello.domain.com/Index/index

访问Test模块 并隐式传入$_GET['var1'] = 1 和 $_GET['var2'] = 'hello' 两个参数。

访问如下地址:

http://think.user.domain.com/Index/index

访问User模块,并隐式传入 $_GET['status'] = 1 和 $_GET['name'] = 'think' 两个参数。

在配置传入参数的时候,如果需要使用当前的泛域名作为参数,可以直接设置为“*”即可。

目前只支持二级域名和三级域名的泛域名部署。

IP访问部署

可以为某些模块配置IP访问规则,例如:

'APP_SUB_DOMAIN_DEPLOY'   =>    1, // 开启子域名配置
'APP_SUB_DOMAIN_RULES'    =>    array(   
    '22.56.78.9'  => 'Admin',  // 22.56.78.9指向Admin模块
),

入口绑定

入口绑定是指在应用的入口文件中绑定某个模块,甚至还可以绑定某个控制器和操作,用来简化URL地址的访问。

绑定模块

例如,我们定义了一个入口文件admin.php,希望可以直接访问Admin模块,那么我们就可以在admin.php中进行模块绑定,定义如下:

// 绑定访问Admin模块
define('BIND_MODULE','Admin');
// 定义应用目录
define('APP_PATH','./Application/');
require './ThinkPHP/ThinkPHP.php';

在3.2.0版本中常量定义需要改成:

$_GET['m'] = 'Admin';

在入口文件中绑定模块后,访问的URL地址中就不需要传入模块名称了。

假设我们要访问Admin模块的Index控制器的test操作方法,访问地址如下: http://serverName/admin.php/Index/test/var/name 如果访问 http://serverName/admin.php/Admin/Index/test/var/name 就会出现下面的错误提示:

绑定控制器

和绑定模块一样,我们还可以绑定控制器(一般是和模块绑定结合使用)。 例如:

// 绑定访问Admin模块
define('BIND_MODULE','Admin');
// 绑定访问Index控制器
define('BIND_CONTROLLER','Index');
// 定义应用目录
define('APP_PATH','./Application/');
require './ThinkPHP/ThinkPHP.php';

我们前面的URL访问就可以换成: http://serverName/admin.php/test/var/name

在3.2.0版本中常量定义需要改成:

$_GET['m'] = 'Admin';
$_GET['c'] = 'Index';

绑定操作

原则上,我们还可以在入口文件中绑定操作(虽然这种情况实际使用中不多见)。

// 绑定访问Admin模块
define('BIND_MODULE','Admin');
// 绑定访问Index控制器
define('BIND_CONTROLLER','Index');
// 绑定访问test操作
define('BIND_ACTION','test');
// 定义应用目录
define('APP_PATH','./Application/');
require './ThinkPHP/ThinkPHP.php';

我们前面的URL访问就可以换成: http://serverName/admin.php/var/name

3.2.0版本不支持操作绑定。

替换入口

3.2版本支持根据当前的运行环境生成Lite文件,可以替换框架的入口文件或者应用入口文件,提高运行效率。

我们的建议是在生产环境中关闭调试模式后生成Lite文件。注意,目前SAE平台不支持直接生成Lite文件。

生成Lite文件

要生成Lite文件,需要在入口文件中增加常量定义:

define('BUILD_LITE_FILE',true);

默认情况下,再次运行后会在Runtime目录下面生成一个lite.php文件。

如果你需要修改Lite文件的位置或者名称,可以在应用配置文件中增加配置如下:

'RUNTIME_LITE_FILE'=> APP_PATH.'lite.php'

配置后,生成的Lite文件的位置为 APP_PATH.'lite.php'。

Lite文件的编译文件内容是系统默认的,如果希望改变或者增加其他的编译文件的话,可以在外部定义编译列表文件,例如: 我们在应用配置目录下面增加lite.php定义如下:

return array(
    THINK_PATH.'Common/functions.php',
    COMMON_PATH.'Common/function.php',
    CORE_PATH . 'Think'.EXT,
    CORE_PATH . 'Hook'.EXT,
    CORE_PATH . 'App'.EXT,
    CORE_PATH . 'Dispatcher'.EXT,
    CORE_PATH . 'Model'.EXT,
    CORE_PATH . 'Log'.EXT,
    CORE_PATH . 'Log/Driver/File'.EXT,
    CORE_PATH . 'Route'.EXT,
    CORE_PATH . 'Controller'.EXT,
    CORE_PATH . 'View'.EXT,
    CORE_PATH . 'Storage'.EXT,
    CORE_PATH . 'Storage/Driver/File'.EXT,
    CORE_PATH . 'Exception'.EXT,
    BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT,
    BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT,
);

所有在lite.php文件中定义的文件都会纳入Lite文件的编译缓存中。你还可以对生成的lite文件进行修改。

如果你修改了框架文件和应用函数和配置文件的话,需要删除Lite文件重新生成。

由于SAE等云平台不支持文件写入,因此不支持直接生成Lite文件。

替换入口

Lite文件可以用于替换框架入口文件或者应用入口文件。

替换框架入口文件

Lite文件生成后,就可以把原来的应用入口文件中的框架入口文件修改如下:

require './ThinkPHP/ThinkPHP.php';
// 改成
require './Runtime/lite.php';

替换Lite文件后,应用编译缓存不再需要。

替换应用入口文件

如果你的入口文件没有其他代码和逻辑的话,还可以直接把lite.php文件作为应用的入口文件访问。 把lite.php 文件复制到应用入口文件的相同目录,并直接改名为index.php即可和原来一样正常访问(原来的应用入口文件可以备份以备用于重新生成Lite文件的时候使用)。

注意:如果你的环境或者目录位置发生变化,以及更改了核心框架和应用函数、配置等文件后,则需要重新生成Lite文件。

参考文档