方说明ThinkPHP去除url中的index.php

关于ThinkPHP去除url中的index.php 的问题。ThinkPHP3的官方文档里专门有说明了。

5.9 URL 重写
通常癿 URL 里面含有 index.php,为了达到更好的 SEO 效果可能需要去掉 URL 里面的 index.php ,
通过 URL 重写的方式可以达到这种效果,通常需要服务器开启 URL_REWRITE 模块才能支持。
下面是 Apache的配置过程,可以参考下:
1、httpd.conf 配置文件中加载了 mod_rewrite.so 模块
2、AllowOverride None 将 None 改为 All
3、确保 URL_MODEL 设置为 2
4、把.htaccess 文件放入口文件同级目录下
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
重启 Apache后,原来的

http://serverName/index.php/Blog/read/id/1

就可以通过访问

http://serverName/Blog/read/id/1

简化了 URL 地址。

Thinkphp中连续使用标签出错,以及使用多维数组要注意

搞后台的权限功能,最后的模板标签竟然卡壳了。最后是konakona提醒看生成的缓存。才发现TP没有把<if>解析,查看原来是两个<if>嵌套了。想办法把另一个改成<eq>。OK通过。

上次也是又个小问题,3维以上的数组,用$array_name.1.2这样会出错,找了很久问题,然后改成中括号的如:$array_name[1][2]就好了~

是为记。

Thinkphp中使用RPC——XMLRPC

RPC
远程过程调用,简单的说,就是A服务器上需要执行一个过程(函数)。向B服务器请求,B服务器执行这个过程,把结果返回A服务器。这个整个过程对用户来讲是透明的,也就是说,用户只关注A服务器上,不需要关心这个(过程)函数是在A服务器执行。
XML-RPC
XML-RPC是Userland Software公司设计的一种格式:是一种使用HTTP协议传输XML格式文件来获取远程程序调用(Remote Procedure Call)的传输方式。官方网站是www.xmlrpc.com。

在http://phpxmlrpc.sourceforge.net/上面有个PHP XML-RPC的框架(类集合)用于使用PHP语言来写XML-RPC客户端和服务端。现在的稳定发行版本是2.2,下载地址是http://sourceforge.net/projects/phpxmlrpc/files/phpxmlrpc/2.2.2/xmlrpc-2.2.2.tar.gz/download

ThinkPHP
和TP结合的话,把lib包放入vendor。
我这里把源服务器和目标服务器都放入同一个文件里了。

代码如下:

[php]
/**
* 这是一个XML-RPC的最简单的例子。
* 没有具体调试,用的时候需要再进一步调试。
*/
class rpcAction extends commonAction {

public function __construct() {
parent::__construct();
vendor(‘RPC.xmlrpc’, "", ".inc");
vendor(‘RPC.xmlrpcs’, "", ".inc");
}

/**
* 主要的处理函数,把参数从远端传过来,转换成php格式
* 再转换成XMLRPC格式,传输回去
* @param $xmlrpcmsg
* @return xmlrpcresp
*/
function foo($xmlrpcmsg) {
$par1 = $xmlrpcmsg->getParam(0); //获取第一个参数
$val1 = $par1->scalarval(); //转换成PHP对应的值

$par2 = $xmlrpcmsg->getParam(1); //获取第二个参数
$val2 = $par2->scalarval(); //转换成PHP对应的值

$par3 = $xmlrpcmsg->getParam(2); //获取第二个参数
//转换成PHP对应的值
for ($i = 0; $i < $par3->arraySize(); $i++) {
$v = $par3->arrayMem($i);
$val[] = $v->scalarVal() . "
";
}

$msg1 = new xmlrpcval(strrev($val1), "string");
$msg2 = new xmlrpcval(strrev($val2), "int");

$msg = new xmlrpcval(array($msg1, $msg2), "array"); //返回一个array

return new xmlrpcresp($msg);
}

/**
* 这个是目的服务器发送数据的
*/
public function set() {
new xmlrpc_server(
array(
"example.test" => array("function" => "foo"),
)
);
}

/**
* 这个是源服务器请求的
*/
function get() {
$params = array(
new xmlrpcval("hello rpc", "string"),
new xmlrpcval(123, "int"),
new xmlrpcval(
array(
new xmlrpcval("test", "string"),
new xmlrpcval(456, "int")
),
"array"),
);

$message = new xmlrpcmsg("example.test", $params);
$client = new xmlrpc_client("/set", "www.hoteltour.new", ’80′);
//$client->setDebug(2);
$res = $client->send($message, 30);

if (!$res->faultCode()) {
$v = $res->value();
for ($i = 0; $i < $v->arraySize(); $i++) {
$vv = $v->arrayMem($i);
echo $vv->scalarVal() . "
";
}
} else {
echo $res->faultcode() . ":" . $res->faultString() . "
";
}
}

}
[/php]

资料参考:

http://www.cnblogs.com/codebean/archive/2011/07/27/2118446.html

http://www.xmlrpc.com/

ThinkPHP水印功能,修复PNG透明水印,和增加JPEG图片质量可调整

TP自带有图片类,有给图片加水印的功能。
这里完善了:
1,png水印透明
2,加水印后质量调整(只限于JPG格式)
代码如下:
红色为原系统的
绿色为修改过的

/**
+———————————————————-
* 为图片添加水印
+———————————————————-
* @static public
+———————————————————-
* @param string $source 原文件名
* @param string $water 水印图片
* @param string $$savename 添加水印后的图片名
* @param string $alpha 水印的透明度
+———————————————————-
* @return string
+———————————————————-
* @throws ThinkExecption
+———————————————————-
*/
static public function water($source, $water, $savename=null, $alpha=80) {
//检查文件是否存在
if (!file_exists($source) || !file_exists($water))
return false;

//图片信息
$sInfo = self::getImageInfo($source);
$wInfo = self::getImageInfo($water);

//如果图片小于水印图片,不生成图片
if ($sInfo["width"] < $wInfo["width"] || $sInfo['height'] < $wInfo['height'])
return false;

//建立图像
$sCreateFun = “imagecreatefrom” . $sInfo['type'];
$sImage = $sCreateFun($source);
$wCreateFun = “imagecreatefrom” . $wInfo['type'];
$wImage = $wCreateFun($water);

//设定图像的混色模式
imagealphablending($wImage, true);

//图像位置,默认为右下角右对齐
$posY = $sInfo["height"] – $wInfo["height"];
$posX = $sInfo["width"] – $wInfo["width"];

/* 为了保持PNG的透明效果 使用imagecopy */
imagecopy($sImage, $wImage, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height']);
//生成混合图像,这是系统的
// imagecopymerge($sImage, $wImage, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height'], $alpha);
//输出图像
$ImageFun = ‘Image’ . $sInfo['type'];
//如果没有给出保存文件名,默认为原图像名
if (!$savename) {
$savename = $source;
@unlink($source);
}
//保存图像,如果是jpg,则设置一下水印质量
if ($sInfo['type'] == “jpg” || $sInfo['type'] == “jpeg”) {
imagejpeg($sImage, $savename, 90);//第3个参数即使质量大小,因为只有imagejpeg支持这个参数
} else {
$ImageFun($sImage, $savename);
}
//$ImageFun($sImage, $savename);
imagedestroy($sImage);
}

最后,感谢KONAKONA提供。

TinkPHP2.1多数据库连接问题(下)

TP2.1多库链接的问题。还是没完。
BTW,后面小熊同学也研究了一下,虽然没有真正解决,但是发现了很多新的启示。并把几张折中的解决方法列举出来,很好:
Thinkphp2.1跨库插入数据问题解决
今天又发生了一件很郁闷的事情(原来一件发现了,当时觉得不值一记。但是现在重复发生,遂记罢,烂笔头)
问题简单描述:当使用异库(当前数据库不是配置指定的)操作时。模型的实例化,一定要放在构造函数中,并且在父类构造函数前。其他地方都会出错。
比如:控制器如下:

public function __construct() {
        parent::__construct();
        $this->model_order = D("order");//这个模型是另一个数据库
}

而这样才是对的

public function __construct() {
        $this->model_order = D("order");
        parent::__construct();
}

可惜偶滴才疏学浅并不知道其中缘由(读TP源代码蛮痛苦的)。猜想大概是实例化控制器之后,会有一个“只读”的数据库名。因此,要在构造的时候,就吧这个值替代掉了。

总之,在TP中使用多个数据库连接,是比较纠结的一件事情。

TinkPHP2.1多数据库连接问题(中)

昨天模型的非当前数据库的问题。不止是create,而且所有有关更新操作的如save,add都出现了问题。
找了很多方法,比如用
addConnect方法新建一个连接,但是我这里显示的是:
Model:addConnect您所请求的方法不存在!
找了资料没有解决的办法,看了一下model的源码,里面是有这个addConnect方法的啊~!!
最后暂时解决了TP异库的问题。
在需要操作非当前库的,建立一个模型。
模型里有:
protected $tableName;
protected $connection = ”mysql://username:passwd@localhost:3306/DbName”;

注意放这两个就好了,不用protected $dbName。原来我也加了$DbName的值。
结果把model打印出来一看,居然是无法找到DbName.$dbName.$tableName。
只放$tableName和$dbName也不行~!!
神奇的是,只放$tableName和$dbName的话,add操作也可以进行,但是ok了之后,库里数据都是空的。
也就是是说,model还是读不出字段~~

总算解决了。但是不好的就是数据库连接放太多地方了,不利于维护。
或许,可以放在配置文件那里,用C(“connectionB”)这样的来获取~!结构比较清晰
(实践了一下。这样并不行,在model里,不能用C这个方法)

参考资料:

http://www.phpvi.com/viewthread.php?tid=26&extra=&page=1

http://www.phpfans.net/ask/MTM0MDk1Mg.html

TinkPHP2.1多数据库连接问题(上):Model模型的create方法不能用在非当前数据库的情况

发现一个问题,Model模型的create方法不能用在非当前数据库的情况。
为了解决这个问题,也想顺便熟悉一下TP。
进去看了一下TP的源码。
涉及到的有:
lib/think/db/db.class.php
其中db.class.php有很多个,精简模式(lite)的,简洁模式(thin)的,等等。
但是用的其实是drvie里的dbmysql.class.php。

TP中模型的create思路是这样的,首先看看有没有$_post参数。如果有的话,放入一个数组。然后查询表的字段。和这个数组一一对比,如果有,则存进一个新的数组里。

因为是异库。所以查询表字段的结果直接就是空了。然后这create()的结果也是空。

最后没有解决的办法,TP是提供了一个“分布式数据库”的功能。但是这不是我们要的,我们的两个数据库其实是不一样的,并不是分布式架构。

重点是dbmysql.class.php里的getFields方法。不能把非当前库的字段检索回来,这就是一个疑问了。

但是为什么只影响了creat。而没有影响其他。比如我直接M(“非当前库”)->findAll()这样的操作是可以的。
没有时间去找这个问题答案。猜想应该是没有用到需要返回字段的地方吧。

ThinkPHP框架,MVC架构,与面向对象的浅思考

用TP也有一段时间了,的确大大提高工作效率。

但是经过一段时间,处理了一些比较复杂的业务逻辑后发现。MVC架构下。网站怎么架构呢?

我们都知道M是模型,V是视图,C是控制器。V是很好理解的,前端的显示页面,HTML代码。M是业务模型。C是连接M和V的控制器,我的理解是类似与转发的机制。

问题来了,既然是转发,那么意味着,控制器的工作应该把前端V的请求使用M对应的功能来解决。工作量应该是最少的。如下图:

mvc

理想的mvc模式

但是实际的情况是:因为种种原因,也许是为了方便,也许因为快速开发,而我发现如果把业务逻辑写在模型上的话。使用ZendStudio或是NetBeans等IED工具,不能直接使用代码提示功能,不能直接“追踪”过去。这是一个很现实的问题,意味着我要必须记得model的所有方法名,否则我要手动打开对应的model文件,寻找对应的方法名。

所以实际项目中,我们是这样架构的:

现实mvc模式

现实mvc模式

把大部分的业务逻辑处理都放在action里,而M只起到了快速操作数据库的功能。

最近看了PHPChina上一篇文章,和我的疑问不谋而合。点击这里查看

我的解决办法是:

文件结构

文件结构

  1. 在控制器中,统一方法前缀。show_:显示页面;action_页面发回去请求;ajax_:页面发回的AJAX请求。如果是业务逻辑比较复杂或需要共用的,独立出一个方法来。用private限定。
  2. 如果是更为复杂的业务逻辑,多个控制器需要用到的,比如订单,用户,登录等。类名用common前缀,这些的“控制器”类并不直接和前端V视图接触。而是提供给其他需要使用相关的类调用。一般用继承方法。可以直接使用。
  3. 但是因为PHP是单继承,这又是一个问题了,如果一个控制器需要订单,用户。那么它只能继承一个类,不能同时继承两个类。这又是一个问题。解决这个问题的办法有两个:1:它继承A,A又继承B。2:或是在控制器里需要用到的时候New 一个控制器类。但是这样的话,又绕回到刚刚不使用model是因为无法追踪类的问题上……

thinkphp中CURD简写需要注意的

$one = $this->model_img->find($img_id);

如果$img_id无值。则输出sql为:

SELECT * FROM `hotel_img` LIMIT 1

又如join的方法中,tabal_a的主键应该是pk_a。可是如果这样写的话:

$city = M(“tabal_a as a”)->join(“tabal_a as b on a.pk_a=b.pk_a”)->find($id);

输出的SQL却为:

SELECT * FROM tabal_a as a LEFT JOIN tabal_b as b on a.pk_a=b.pk_a WHERE ( `id` = ’2′ ) LIMIT 1

因为两个表中都有pk_a的字段名,所以不值得的话,会出错滴。

所以,为了保险起见,检索一条记录的时候,最好多打几个字,用where()方法吧。

附ThinkPHP的find()方法源码:

[php]
/**
+———————————————————-
* 查询数据
+———————————————————-
* @access public
+———————————————————-
* @param mixed $options 表达式参数
+———————————————————-
* @return mixed
+———————————————————-
*/
public function find($options=array()) {
if (!empty($options) && ( is_numeric($options) || is_string($options))) {
$where[$this->getPk()] = $options;
$options = array();
$options['where'] = $where;
}
// 总是查找一条记录
$options['limit'] = 1;
// 分析表达式
$options = $this->_parseOptions($options);
$resultSet = $this->db->select($options);
if (false === $resultSet) {
return false;
}
if (empty($resultSet)) {// 查询结果为空
return null;
}
$this->data = $resultSet[0];
$this->_after_find($this->data, $options);
return $this->data;
}
[/php]

自定义函数解决ThinkPHP模板标签加减运算

实际项目中,我们经常需要标签变量加减运算的操作。但是,在ThinkPHP中,并不支持模板变量直接运算的操作。
幸运的是,它提供了自定义函数的方法,我们可以利用自定义函数解决:
ThinkPHP模板自定义函数语法如下:
格式:{:function(…)} (参考官方帮助文档:http://thinkphp.cn/Manual/196)
利用这个,我们来试做加法和减法。

  1. 在ThinkPHP中定义函数。在项目的common文件夹下新建common.php文件(这样系统会自动加载)。定义两个函数:
    [code lang="php"]
    /**
    * 相加,供模板使用
    * @param <type> $a
    * @param <type> $b
    * @author:liufangfang.net@gmail.com
    */
    function template_add($a,$b){
    echo(intval($a)+intval($b));
    }

    /**
    * 相减,供模板使用
    * @param <type> $a
    * @param <type> $b
    * @author:liufangfang.net@gmail.com
    */
    function template_substract($a,$b){
    echo(intval($a)-intval($b));
    }
    [/code]

  2. 在模板中使用函数:
    {:template_add($var1,$var2)}

即可显出变量var1于var2的和。
需要注意的是:如果变量是数组,要这样显示:
{:template_add($var[var1],$var[var2])}
而不是我们通常是用点语法。
利用自定义函数,你自己还可以定义很多不一样的功能,试试吧~~