批量截图软件webmonitor

自己开发了一款批量截图软件,用来对一组url批量截图。当web项目修改后,运行软件,重新截图一遍,查看是否有样式错乱。使用aau开发(http://www.aau.cn),在此特别推荐一下aau,一款国人研发的开发语言。

webmonitor源码地址:git://gitcafe.com/lcc/WebMonitor.git
webmonitor项目页面:https://gitcafe.com/lcc/WebMonitor

说明:1. git获取项目源代码 2. 从www.aau.cn上下载aau开发工具,用开发工具打开项目点击“运行”试用程序,或者点击“发布”生成应用程序。

使用截图:

创建项目

添加url

截的图片

ThinkPHP中关于Widget的小问题

又折腾了下Widget,纪录下遇到的两个小问题。

1. Layout中嵌入Widget,Widget未显示声明NOLAYOUT时,出现循环调用。
例:Lib/Tpl/_layout.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h1>这是layout</h1>
  <div>
    {__CONTENT__}
  </div>

  <div>
    {:W('Test')}
  </div>
</body>
</html>

Lib/Widget/Test/test.html

<ul>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
</ul>

这个时候,编译出来的Widget模板大概是这样

<?php if (!defined('THINK_PATH')) exit();?><!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h1>这是layout</h1>
  <div>
    <ul>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
  <li><a href="javascript:;">这是Widget中的内容</a></li>
</ul>

  </div>

  <div>
    <?php echo W('Test');?>
  </div>
</body>
</html>

Widget模板编译的时候被填充在了Layout的{__CONTENT__}中,下面W('test')的Widget调用依然存在。于是发生死循环没有报错页面一片空白,逐行调试了好久才找到问题。
解决方法:在 Lib/Widget/Test/test.html 开头添加一行{__NOLAYOUT__}

2. Widget的调用方式和传参。
我参考的是官方3.1.2的手册,手册上的示例是{:W('ShowComment')},大意是调用ShowComment得到返回的内容。在 Action 中使用 $widgetContent = W('ShowComment'); $this->assign('widgetContent',$widgetContent);但是$widgetContent的内容没有出现在模板变量{$widgetContent}出现的位置,查看函数时才看到W函数在默认情况下是echo出widget的内容。模板中正确的调法是{~W('ShowComment')},如果只是要取到Widget的内容应该使用W('ShowComment',array(),true);。

ThinkPHP用Behavior扩展Layout

ThinkPHP新版的模板引擎添加了layout试用了下layout功能还是蛮强大的,但还是用法还不太灵活需要在配置文件中手动指定。自己用Behavior做了一个小功能来扩展layout,在Action类中指定$layout属性的值即可自动启用layout,也可以在单个Action方法中设置layout的值,设置为空值时不启用layout。

1. 创建ActionEx
文件:Lib/Model/ActionEx.class.php

<?php
  class ActionEx extends Action {
    public $layout;
    public $_runViewAssist;

    // 初始化动作绑定
    public function _initialize() {
      ActionEx::action($this);
      add_tag_behavior('view_begin','ViewAssist');
    }

    // 暂存action
    static public $_action;
    // 获取action
    static function action(&$action = false) {
      if ($action) {
        self::$_action = $action;
      }
      return self::$_action;
    }

  }
?>

2. 配置自动加载路径
在Conf/config.php中添加 'APP_AUTOLOAD_PATH' => '@.Model', 将Model添加到自动加载路径。

3. 添加Behavior
Lib/Behavior/ViewAssistBehavior.class.php

<?php
  class ViewAssistBehavior extends Behavior {
    protected $options = array();

    public function run(&$params) {
      $act = ActionEx::action();
      if (!$act->_runViewAssist) {
        $act->_runViewAssist = true;
        if ($act->layout) {
          C('LAYOUT_ON', 1);
          C('LAYOUT_NAME', $act->layout);
          // var_dump($act->layout);exit;
        }
      }
    }
  }
?>

4. 测试Layout
Lib/Action/TestAction.class.php

<?php
  class TestAction extends ActionEx {
    public $layout = '_layout';
    public function index() {
      $this->display();
    }

    public function test2() {
      // 禁用layout
      $this->layout = '';
      $this->display();
    }
  }
?>

Tpl/_layout.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h1>这是layout</h1>
  <div>
    {__CONTENT__}
  </div>
</body>
</html>

Tpl/Test/index.html

<h3>这是action中的内容</h3>

Tpl/Test/test2.html

<h3>test2</h3>

分别访问localhost/Test/index和localhost/Test/test2可以看到启用layout和未启用layout界面。

附:
文件目录

| | |~Common/
| | |~Conf/
| | | `-config.php
| | |~Lang/
| | |~Lib/
| | | |~Action/
| | | | |-IndexAction.class.php
| | | | `-TestAction.class.php
| | | |~Behavior/
| | | | `-ViewAssistBehavior.class.php
| | | |~Model/
| | | | `-ActionEx.class.php
| | | `~Widget/
| | |+Runtime/
| | |~Tpl/
| | | |~Test/
| | | | |-index.html
| | | | `-test2.html
| | | `-_layout.html
| | `-index.php

启用Layout和禁用Layout的截图


相关链接
ThinkPHP官网:http://www.thinkphp.cn/
 

一个批量转换coffee的Makefile

有一个小需求,将一个目录包括子目录中的coffee文件批量转换到另一个指定的目录中,同时保挂子目录的结构。改了一个类似的Makefile。发一下备忘:

coffeeBaseDir=coffee/
coffeeDir=$(abspath $(coffeeBaseDir))
jsBaseDir=js/
jsDir=$(abspath $(jsBaseDir))

jsFile=$(shell find $(coffeeBaseDir) -type f -name *.coffee | sed 's@^$(coffeeBaseDir)@$(jsDir)/@g' | sed 's@\.coffee$$@\.js@g')

jsDeploy: $(jsFile)

$(jsDir)/%.js: $(coffeeDir)/%.coffee
	@mkdir -p `sed 's@/[^/]\+$$@/@g' <<< '$@'`
	coffee -bp $< > $@

test:
	@echo $(jsFile)

clean:
	@rm js -fr
	@echo 'clean success!'

测试结果:

 

>find coffee -type f
coffee/abc.coffee/3.coffee
coffee/abc.coffee/1.coffee
coffee/abc.coffee/2.coffee
coffee/p1/3.coffee
coffee/p1/1.coffee
coffee/p1/2.coffee
coffee/p2/3.coffee
coffee/p2/1.coffee
coffee/p2/2.coffee
coffee/p3/3.coffee
coffee/p3/1.coffee
coffee/p3/2.coffee

>find js -type f
js/abc.coffee/2.js
js/abc.coffee/1.js
js/abc.coffee/3.js
js/p1/2.js
js/p1/1.js
js/p1/3.js
js/p2/2.js
js/p2/1.js
js/p2/3.js
js/p3/2.js
js/p3/1.js
js/p3/3.js

 

nginx使用ngx_http_empty_gif_module模块

在nginx官网看到有ngx_http_empty_gif_module这个模块,可以默认输出一个空白的gif,某个png透明的插件要用到这种透明的gif文件,简单看了下,配置方法很简单:

location = /_.gif {
    empty_gif;
}

最开始我本地总是提示File not found.针对php框架的rewrite将这个请求重定向到了php请求,在rewrite最开始添加了一行 rewrite ^/_\.gif$ /_.gif break; 将文件重定向一次OK了

参考链接:
ngx_http_empty_gif_module: http://nginx.org/en/docs/http/ngx_http_empty_gif_module.html

 

js点阵绘制5边形

更新说明:
2013-05-27 上传到gitcafe上面拖管 https://gitcafe.com/lcc/somecode/tree/master/jsdraw

写了一段生成象素点来绘制5边形的代码。用到了 Bresenham斜线画法三角函数等知识。代码如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title>JS绘制五边形</title>
  <style type="text/css">
    .paper {
      width: 600px;
      height: 300px;
      border-color: #E0E0E0;
      border: 1px solid #DDD;
      position: relative;
    }
    .point {
      width: 1px;
      height: 1px;
      position: absolute;
      overflow: hidden;
      display: block;
      zoom: 1;
    }
    .red {
      background-color: red;
    }
  </style>
  <script type="text/javascript">
    // 画斜线
    function drawLine(point1, point2) {
      var point, pointElem, paper;

      pointElem = document.createElement('div');
      if ('className' in pointElem) {
        pointElem.className = 'point red';
      }
      else {
        pointElem.setAttribute('class', 'point red');
      }

      paper = document.getElementById('paper');

      var xLen = Math.abs(point2[0] - point1[0]);
      var yLen = Math.abs(point2[1] - point1[1]);
      var x, y, cx, cy, tox, toy, rate, rateVal, isAdd = true;
      // 从x轴遍历
      if (xLen >= yLen) {
        if (point1[0] > point2[0]) { point1 = [point2, point2=point1][0]; }
        if (point1[1] > point2[1]) { isAdd = false; }

        x = cx = point1[0];
        y = cy = point1[1];
        tox = point2[0];
        toy = point2[1];

        rateVal = rate = parseInt( (yLen / xLen) * 1000)
        for (var i=x; i<tox; i++) {
          cx = i;
          point = pointElem.cloneNode();
          paper.appendChild(point);
          point.style.left = cx + 'px';
          point.style.top = cy + 'px';
          rateVal += rate
          if (rateVal >= 1000) {
            cy += isAdd ? 1 : -1
            rateVal -= 1000;
          }
        }
      }
      // 从y轴遍历
      else {
        if (point1[1] > point2[1]) { point1 = [point2, point2=point1][0]; }
        if (point1[0] > point2[0]) { isAdd = false; }

        x = cx = point1[0];
        y = cy = point1[1];
        tox = point2[0];
        toy = point2[1];

        rateVal = rate = parseInt( (xLen / yLen) * 1000)
        for (var i=y; i<toy; i++) {
          cy = i;
          point = pointElem.cloneNode();
          paper.appendChild(point);
          point.style.left = cx + 'px';
          point.style.top = cy + 'px';
          point = null
          rateVal += rate
          if (rateVal >= 1000) {
            cx += isAdd ? 1 : -1
            rateVal -= 1000;
          }
        }
      }
      // 补点
      if (cx != tox || cy != toy) {
        point = pointElem.cloneNode();
        paper.appendChild(point);
        point.setAttribute('style', 'left:' + tox + 'px; top:' + toy + 'px');
        point = null
      }
      pointElem = null;
    }
    // 获取点信息
    function getPointInfo(R, dot) {

      var A = 360 / 5
      var sinLen = Math.sin(A / 180 * Math.PI) * R
      var cosLen = Math.cos(A / 180 * Math.PI) * R
      sinLen = Math.round(sinLen)
      cosLen = Math.round(cosLen)

      var point1 = [dot[0], dot[1] - R]
      var point2 = [dot[0] + sinLen, dot[1]- cosLen]
      var point5 = [dot[0] - sinLen, dot[1] - cosLen]

      var A2 = (180 - A) / 2
      sinLen = Math.sin(A2 / 180 * Math.PI) * R
      cosLen = Math.cos(A2 / 180 * Math.PI) * R
      sinLen = Math.round(sinLen)
      cosLen = Math.round(cosLen)

      var point3 = [dot[0] + cosLen, dot[1] + sinLen]
      var point4 = [dot[0] - cosLen, dot[1] + sinLen]

      return [point1, point2, point3, point4, point5];
    }
    // 画点
    function drawShape(type, R, dot) {
      var pointInfo = getPointInfo(R, dot)
      var point1 = pointInfo[0];
      var point2 = pointInfo[1];
      var point3 = pointInfo[2];
      var point4 = pointInfo[3];
      var point5 = pointInfo[4];
      // 五边形
      if (type == 1) {
        drawLine(point1, point2);
        drawLine(point2, point3);
        drawLine(point3, point4);
        drawLine(point4, point5);
        drawLine(point5, point1);
      }
      // 五角星
      else if (type == 2){
        drawLine(point1, point3);
        drawLine(point3, point5);
        drawLine(point5, point2);
        drawLine(point2, point4);
        drawLine(point1, point4);
      }
    }

    window.onload = function () {
      drawShape(1, 100, [150, 150])
      drawShape(2, 100, [450, 150])
    }
  </script>
</head>
<body>
  <div id="paper" class="paper"></div>
</body>
</html>

效果图:

windows下安装绿色版nodejs

经常折腾系统,来回切换或更换系统。官方的安装程序每次都要重新安装npm包比较麻烦。折腾了下,下载二进制文件,配置环境变量来安装nodejs。

1、下载nodejs
http://nodejs.org/dist/v0.10.7/node.exe 下载的文件放到D:\node目录下

2、下载npm
http://nodejs.org/dist/npm/npm-1.2.22.zip 将压缩包中的 npm.cmd node_modules 解压到D:\node目录下。注意是.zip格式的,不是.tgz格式的,两个包里面的内容不同。

3、设置环境变量
新建2个环境变量 
NODE_HOME 值 D:\node
NODE_PATH 值 %NODE_HOME%\node_modules
在PATH后面追加 ;%NODE_HOME%

4、打开cmd,输入npm ls -g,这时应该能打印出包的信息,说明安装成功。

关于nginx配置PATH_INFO的坑

之前在网上找nginx配置PATH_INFO的方法,有一种是将PATH_INFO的值指定为$fastcgi_script_name,在php.ini中设置cgi.fix_pathinfo的值为1,前天在使用某款依赖PATH_INFO的框架时,果断被坑。将入口文件改为请求 http://localhost/index-dev.php时,PATH_INFO的值为 index-dev.php,框架将index-dev框架识别为controller报错。

附可用的配置方法:

set $path_info "";
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
    set $real_script_name $1;
    set $path_info $2;
}
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_NAME $real_script_name;

几种配置方案PATH_INFO值的对比:

配置类型 请求地址 PATH_INFO PHP_SELF SCRIPT_NAME 说明
Apache /test.php /test.php /test.php Apache的值为参考
  /test.php/abc/123 /abc/123 /test.php/abc/123 /test.php Apache的值为参考
nginx设置PATH_INFO
和SCRIPT_NAME
/test.php no value /test.php /test.php 正常
  /test.php/abc/123 /abc/123 /test.php/abc/123 /test.php 正常
nginx设置PATH_INFO的值为
$fastcgi_script_name
/test.php /test.php /test.php/test.php /test.php PATH_INFO异常
PHP_SELF异常
  /test.php/abc/123 /abc/123 /test.php/abc/123 /test.php PHP_SELF异常

另外:网上所提的 cgi.fix_pathinfo 打开时的露洞,已修补。cgi.fix_pathinfo的值设为0时,请求/test.php/abc/123的地址时,会报 Access denied. 的错误。

LNMP环境创建ThinkPHP项目

看到ThinkPHP发布了3.1.3版本,下载了一个创建项目玩玩。中间还遇到些小问题,记录一下。

1.下载解压缩TP
unzip ThinkPHP3.1.3_Full.zip -d /www/lib/

2.创建项目文件
cd /www/cms/tp
vim index.php

<?php
  define('APP_DEBUG', 1);
  require '../../lib/ThinkPHP/ThinkPHP.php';

3.修改权限
chmod 775 . -R

4.浏览器访问,基本上会出现如下错误
无法加载模块:index.php
错误位置
FILE: /data/www/lib/ThinkPHP/Common/functions.php  LINE: 112

5.编辑配置文件
vim Conf/config.php

<?php
return array(
  //'配置项'=>'配置值'
  'URL_HTML_SUFFIX' => '',
  'URL_CASE_INSENSITIVE' => 1,
);
?>

至此大功告成

附本人nginx host配置

# tp.cms.com
server {
    listen       80;
    root /www/cms/tp;
    index  index.html index.htm index.php index-dev.php;
    server_name  .tp.cms.com;

    location ~* \.php {
      fastcgi_pass 127.0.0.1:9000;
      #fastcgi_pass unix:/tmp/nginx_sockets_php5-fpm.sock;
      fastcgi_index index.php;
      include fastcgi.conf;
      set $path_info "";
      set $real_script_name $fastcgi_script_name;
      if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
        set $real_script_name $1;
        set $path_info $2;
      }
      fastcgi_param PATH_INFO $path_info;
      fastcgi_param SCRIPT_NAME $real_script_name;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    if (!-e $request_filename) {
      rewrite  ^(.*)$  /index.php$1 break;
    }
}

更新记录:
2015-12-28:修改nginx配置的错误

makefile将相对路径转换为绝对路径

工作中用makefile执行打包、压缩、转换等功能,一个需求涉及到多层相对路径嵌套,于是想到将相对路径转换为绝对路径。百度谷歌数遍,找到一曲径通幽的方法。

PUBLICDIR = $(shell cd ../public; pwd)

*2012年11月16日更新

经依云大大提点,又上网搜索了一下Makefile相关函数。Makefile自带有两个函数可以得到绝对路径。
1. realpath 函数获取文件名序列中存在的文件和目录的真实路径,会判断文件和目录是否存在,如果不存在,则返回空。
2. abspath 函数获取文件名序列中存在的文件和目录的真实路径,函数不会检查文件或者目录是否存在。
示例:
PUBLICDIR = $(abspath ../public; pwd)

经本人测试,realpath abspath 能跨过软链接,获取文件的真实路径。

例如:
ln -s /usr/local/www /www

Makefile:

WWWDIR = $(abspath /www)
test:
    echo $(WWWDIR) #output /usr/local/www

make test #output /usr/local/www