Archive for October, 2008

使用php生成网站缩略图

Friday, October 17th, 2008

今天bobhero要我看一下关于这个问题的解决方案, 其实这个问题以前也有想过,不过最后没有找到解决的方法, 今天在网上搜的时候发现这样一段代码。

<?php
// 调用IE
$browser = new COM(“InternetExplorer.Application”);
$handle = $browser->HWND;
// 前台执行
$browser->Visible = true;
// 全屏
$browser->Fullscreen = true;
$browser->Navigate(“http://www.m4ker.net”);

/* Still working? */
while ($browser->Busy) {
com_message_pump(4000);
}
// imagegrabwindow是对窗口进行截图
$im = imagegrabwindow($handle, 0);
// 关闭浏览器
$browser->Quit();
// 生成图片
$new_img = imagecreatetruecolor(200,150);
imagecopyresampled($new_img,$im,0,0,0,0,200,150,1024,768);
imagejpeg($new_img , ‘image/’.time().’.jpg’,100);
imagedestroy($new_img);

?>

很神奇竟然真的好用, 不过只限Windows, 原理也就是调用IE的COM, 打开网站然后截图这样。

url重写后的路径问题

Friday, October 17th, 2008

以前用FleaPHP的url_rewrite模式一直有一个很头痛的问题, 就是页面上相关资源的路径问题.

问题大概是这样的, 为了让url更加友好我们使用apache的mod_rewrite将类似

http://localhost/?controller=default&action=index&a=1

这样的路径重写成

http://localhost/default/index/a/1

或者

http://localhost/default/index/a/1.html

这样, 但是如果是这样那么浏览器请求页面相关资源的基地址就发生了改变, 从原来的documentroot下变成了documentroot/default/index/a, 如果你要在页面上显示一个图片 1.jpg, 那么原来本来应该在documentroot/1.jpg下找到的文件却变成了documentroot/default/index/a/1.jpg, 那结果肯定是找不到的.

为了解决这个问题以前用过很多方法, 用的最多的就是使用绝对路径来解决这个问题, 这是有一个前提的, 就是程序一定要放在虚拟机的根目录下, 这样在html中要将所有的资源都是用/开头, /的意思是从根目录下开始寻找, 在localhost下的任何一个程序在任何目录中使用/1.jpg都会被指向documentroot/1.jpg, 这里再强调一个概念, “./”是当前目录, “../”是上级目录, “/”是根目录.

上面这个方法实际上已经可以解决这个问题了, 但是有局限, 就是程序的目录是固定的, 一定要在虚拟机根目录下, 这样或多或少会带来一些麻烦, 至少我觉得调试不方便. 于是又有了第二个解决方案, 也就是上面方案的升级版. 我们在全局定义一个常量 define(‘PRE_DIR’, ‘/’); 这样的话要将程序中所有的资源路径都写成类似 <?php echo PRE_DIR;?>dir/filename.jpg, 这样的话资源会被定为到 /dir/filename.jpg, 如果要将程序放在二级目录 test/下的话, 只要将PRE_DIR的值改成’/test/’就可以了.

其实在这之后又有了升级版, 但是不打算介绍太多, 因为这不是重点, 在手动改目录之后大家就想到要程序自动检测当前目录, 这个以前有做过, 是个不错的想法, 代码不少, 但是找不到了.

还有个东西我觉得比较神奇的, smarty有一个自动替换的插件, 可以自动在所有模板的资源链接前面加前缀, 当然前提是你已经定义了这个前缀, 插件名不记得了, 太久不用找不到了.

还是说重点吧, 昨天bobhero给我提供了一个新的思路, 利用mod_rewrite重新对资源进行定向, 后来到网上找相关的资料, 没有找到, 只找到了一些mod_rewrite的教程什么的. 研究了一下午也没研究出来, 因为url太复杂了, 很多情况都要考虑进去, 正则说什么就写不明白了, 今天早上终于搞定了.

_________.htaccess_____________________

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^.]*)(\.html)?$ index.php/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/(.*\..*)$ $2

________end of .htaccess_____________

起作用的其实就这些东西,  可能还会有错误, 不过的确生效了.简单解释一下, RewriteCond %{REQUEST_FILENAME} !-f是条件语句, 意思是说如果请求的文件不存在下面的规则才生效. 第一条规则RewriteRule ^([^.]*)(\.html)?$ index.php/$1 [L]是FLEAPHP的重写规则.

下面两条才是为了解决路径问题的, RewriteRule ^([^/]*)/(.*\..*)$ $2的作用大概是这样, 比如url是这样controller/action/page/1,那么该页的style/css.css可能变成了controller/action/page/style/css.css, 这条语句就是要将controller/action/page/style/css.css指向action/page/style/css.css, 而由于某种机制请求每更换一次目录就会再执行一次根目录下的.htaccess中的重写规则, 由于action/page/style/css.css也不存在所以又被定向到page/style/css.css, 同理page/style/css.css也不存在, 再向上 style/css.css, 由于文件存在而不再执行重写规则, 向用户返回style/css.css的内容.

总的来说最后的这个方法除了apache受点累还是很完美的, 这样大概可能每个资源请求都会被重定向4次以上, 目前还不清楚对执行效率有多大的影响.

参考资料:

竹笋炒肉:Apache的Mod_rewrite学习

识别用户是否是通过手机访问

Thursday, October 9th, 2008

今天花了些时间研究这个问题, 不过目前为止没有找到比较完美的解决方案, 简单说说吧.

现在网上一般有这样几种方法:

第一种是根据浏览器发送的HTTP_USER_AGENT来判断用户是否是通过手机访问网站. 这种方法比较普遍, 可以通过匹配关键字适应大多数手机, 但由于HTTP_USER_AGENT格式并没有标准规范并且不是HTTP协议必须的参数, 所以无法适应所有手机或者所有浏览器, 有些手机甚至不发送HTTP_USER_AGENT.

注: 可以在网上搜到别人搜集的各型号手机和浏览器的HTTP_USER_AGENT

第二种方法是根绝浏览器发送的HTTP_ACCEPT, HTTP_ACCEPT可以判断浏览器支持哪些格式的页面, 比如WAP, HTML, XHTML, XML等, 但对于判断用户是否通过手机访问并不是非常准确, 因为HTTP_ACCEPT不是同样必须的, 多数浏览器并不会在HTTP_ACCEPT中进行过多的描述, 比如一个浏览器如果声明了自己支持wml那它可能支持wml, 但是如果不声明wml并不代表就一定不支持wml.

比如Firefox3的HTTP_ACCEPT是这样的:

text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8 

而黑莓8800的HTTP_ACCEPT是这样的

application/vnd.rim.html, text/html, application/vnd.wap.xhtml+xml, text/vnd.sun.j2me.app-descriptor, image/vnd.rim.png,image/jpeg, application/x-vnd.rim.pme.b, application/vnd.rim.ucs, image$1.gif;anim=1, application/vnd.rim.jscriptc;v=0-8-8, application/x-javascript, application/vnd.rim.css;v=1, text/css;media=handheld, application/vnd.wap.wmlc;q=0.9, application/vnd.wap.wmlscriptc;q=0.7, text/vnd.wap.wml;q=0.7, */*;q=0.5 

还有一种方法有人说可以判断用户的IP, 原理也简单, 因为在国内GPRS上网是通过代理连接的, 所以用户的IP可能是固定的几个, 但是我并不确定手机不能够通过其他方式上网, 比如3G, 或者说我用手机模拟器登录的时候就有可能出错, 或者说如果我用手机当猫那么会将我通过电脑进行的访问当作手机来处理.

还有一种方法我觉得很不错, 如果浏览器支持javascript的话, 可以判断显示器的尺寸, 没有人会用一个19寸大的手机吧?

说来说去, 还是没有找到完美的解决方法, 不过综合这几种方法写了一个函数.

/**
 * 是否是通过手机访问
 *
 * @return bool 是否是移动设备
 */
function isMobile()
{
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
        return true;
    }

    $keywords = array('nokia', 'sony', 'ericsson', 'mot',
        'samsung', 'sgh' ,'lg', 'sie-',
        'philips', 'panasonic', 'alcatel', 'lenovo',
        'cldc', 'midp', 'wap', 'mobile');
    // 从HTTP_USER_AGENT中查找手机浏览器的关键字
    if (preg_match("/(" . implode('|', $keywords) . ")/i",
        strtolower($_SERVER['HTTP_USER_AGENT']))) {
        return true;
    }

    if (isset($_SERVER['HTTP_ACCEPT'])) {
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false)
        && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false
        || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml')
        < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
            return true;
        }
    }

    return false;
}