CodeIgniter中的配置类

CI中的配置文件默认都在application/config/路径下,当然也可以在你的自定义路径下,其中config.php是自动加载的,如果需要程序初始化的时候自动加载你需要的配置文件,那么在autoload.php中,在$autoload[‘config’] = array();中加入你需要的文件名即可。

在自定义配置文件中需要注意的一点就是,你所有的配置数据都需要放到全局的配置变量$config中,比如在application/config/路径下,新建了一个配置文件customized.php.内容如下:

$customize = array(
    'customize1' => 1,
    'customize2' => 2,
    'customize3' => 3,
    'customize4' => 4,
    'customize5' => 5,
    'customize6' => 6,
    'customize7' => 7,
);

假定手动加载该文件$this->config->load(‘customized’);会发现有如下报错

Your application/config/sns.php file does not appear to contain a valid configuration array.

提示这个配置文件没有包含一个合法的配置数组,那么合法的配置数组是怎样的呢,通过看核心配置类源码system/core/Config.php中的load方法

/**
	 * Load Config File
	 *
	 * @access	public
	 * @param	string	the config file name
	 * @param   boolean  if configuration values should be loaded into their own section
	 * @param   boolean  true if errors should just return false, false if an error message should be displayed
	 * @return	boolean	if the file was loaded correctly
	 */
	function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
	{
		$file = ($file == '') ? 'config' : str_replace('.php', '', $file);
		$found = FALSE;
		$loaded = FALSE;

		$check_locations = defined('ENVIRONMENT')
			? array(ENVIRONMENT.'/'.$file, $file)
			: array($file);

		foreach ($this->_config_paths as $path)
		{
			foreach ($check_locations as $location)
			{
				$file_path = $path.'config/'.$location.'.php';

				if (in_array($file_path, $this->is_loaded, TRUE))
				{
					$loaded = TRUE;
					continue 2;
				}

				if (file_exists($file_path))
				{
					$found = TRUE;
					break;
				}
			}

			if ($found === FALSE)
			{
				continue;
			}

			include($file_path);

			if ( ! isset($config) OR ! is_array($config))
			{
				if ($fail_gracefully === TRUE)
				{
					return FALSE;
				}
				show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.');
			}

			if ($use_sections === TRUE)
			{
				if (isset($this->config[$file]))
				{
					$this->config[$file] = array_merge($this->config[$file], $config);
				}
				else
				{
					$this->config[$file] = $config;
				}
			}
			else
			{
				$this->config = array_merge($this->config, $config);
			}

			$this->is_loaded[] = $file_path;
			unset($config);

			$loaded = TRUE;
			log_message('debug', 'Config file loaded: '.$file_path);
			break;
		}

		if ($loaded === FALSE)
		{
			if ($fail_gracefully === TRUE)
			{
				return FALSE;
			}
			show_error('The configuration file '.$file.'.php does not exist.');
		}

		return TRUE;
	}

加载自定义配置的这个方法,非要在自定义配置文件中找到$config这个变量才罢休,否则就是不合法的。所以,只需要在我们原来的自定义配置文件加上一行就ok了,如下

$customize = array(
    'customize1' => 1,
    'customize2' => 2,
    'customize3' => 3,
    'customize4' => 4,
    'customize5' => 5,
    'customize6' => 6,
    'customize7' => 7,
);
$config['customize'] = $customize;

如此写法,不免觉得有些僵硬。。。

PS:现在Ellislab已经放弃了CI的维护,希望找到到下一个维护CI的组织,CI3.0已经看不到希望了。

如何用linux神器AWK查询开房记录

前一段时间火热的2000w开房记录,加菲同学给了我一份,话说当初拿到文件的时候,我二话没说,写了一个php脚本,在windows下往mysql插,不曾想,插了1w余条便502而死。而后又改进脚本,在cli模式下,开了11个窗口,跑了十几分钟的样子终于都入了mysql,但是在未建索引的情况下,搜索varchar类型的字段,每次搜索都超过2分钟。如此低效,令人发指。正好近期学习完awk章节,期间拿记录文件来测试,效率极高,今日总结此文,权当巩固知识之用了,如若看官能从此文习得一招两式,荣幸之至。

关于AWK,介绍如下:

AWK的作者(Alfred V.Aho && Peter J.Weinberger && Brain W.Kernighan),他是一种模式扫描与处理语言,搜索一个或者多个文件,以查看这些文件中是否存在匹配指定模式的记录(通常是文本行)。每次发现匹配的记录时,它通过执行动作的方式(比如将该记录写到标准输出或者将某个计数器递增)来处理文本行。与过程语言相反,AWK属于数据驱动语言:用户描述想要处理的数据并告诉AWK当它发现这些数据时如何处理他们。

我手里拿到的是一份2000w开放记录的csv文件压缩包(对于其完整性不要太抱期望),因为此次泄漏的记录本身只是部分时间段的部分文件而已。文件列表如下

-rw-------  1 aladdin aladdin 303M Jun 27 21:23 1000W-1200W.csv
-rw-------  1 aladdin aladdin 294M Jun 27 21:30 1200W-1400W.csv
-rw-------  1 aladdin aladdin 333M Jun 27 20:24 1-200W.csv
-rw-------  1 aladdin aladdin 306M Jun 27 21:43 1400W-1600W.csv
-rw-------  1 aladdin aladdin 296M Jun 27 22:07 1600w-1800w.csv
-rw-------  1 aladdin aladdin 285M Jun 27 22:20 1800w-2000w.csv
-rw-------  1 aladdin aladdin 297M Jun 27 20:32 200W-400W.csv
-rw-------  1 aladdin aladdin 297M Jun 27 20:49 400W-600W.csv
-rw-------  1 aladdin aladdin 295M Jun 27 21:02 600W-800W.csv
-rw-------  1 aladdin aladdin 297M Jun 27 21:15 800W-1000W.csv
-rw-------  1 aladdin aladdin 7.2M Jun 27 22:25 last5000.csv

如果你迫不及待想用你的姓名,生日,身份证号等等信息查询你是否在记录中,一条语句便可

awk '/王X/ && /靖江/' 1000W-1200W.csv 1200W-1400W.csv 1-200W.csv 1400W-1600W.csv 1600w-1800w.csv 1800w-2000w.csv 200W-400W.csv 400W-600W.csv 600W-800W.csv 800W-1000W.csv last5000.csv

这语句很易懂,就是在这些数据文件中将匹配模式  ‘/王X/ && /靖江/’  的记录打印出来,我们先来看结果,10秒多的时间,搜寻近3G的文件内容之后,cpu和内存占用没有明显的数据变化,结果已然如列:

王X,,,ID,321XXXXXXXXXXX5028,F,19xxxxxx,江苏省靖江市XXXXXX,,F,,CHN,32,3201,,,,,,,,,,汉,,,,,,,0,2012-12-29 17:50:49,13773207
王X,,,ID,321XXXXXXXXXXX5218,M,19xxxxxx,江苏省靖江市XXXXXXXXXXXX,,F,,CHN,32,321282,,,,,,,,,,汉,,,,,,,0,2012-6-6 13:52:38,14885090
王X,,,ID,321XXXXXXXXXXX043X,M,19xxxxxx,江苏省靖江市XXXXXXXXXXX,,F,,CHN,32,3201,,,,,,,,,,汉,,,,,,,0,2011-1-19 3:05:42,5593856
王X,,,ID,321XXXXXXXXXXX1817,M,19xxxxxx,江苏省靖江市XXXXXXXXXX,,F,,CHN,32,320105,,,,,,,***********,,,汉,,,,,,,0,2011-6-12 13:52:38,8115281
王X,,,ID,320XXXXXXXXXXXX92X,F,19xxxxxx,江苏省靖江市XXXXXXXXXXXX,,F,,CHN,32,3201,,,,,,,,,,汉,,,,,,,0,2011-9-14 7:21:50,9908197

姓名,身份证号,性别,生日,户口住址,开房时间……一目了然,我们来分析下这个语句

awk '/pattern/' file-lists  # 这里的pattern支持与/或等各种逻辑,斜杠表示:这里是个正则表达式

其实这里是有个缺省动作{print}的,打印(即复制到标准输出)匹配出的记录,原理了然。

 

为方便实验,我们下面拷贝下last5000.csv这个文件,用拷贝的文件来做实验。假定拷贝的文件是test.csv.用下面这个命令

awk '{print}' test.csv | less

大概看下文件,列一下字段名,内容截屏就不放了

Name,CardNo,Descriot,CtfTp,CtfId,Gender,Birthday,Address,Zip,Dirty,District1,District2,District3,District4,District5,District6,FirstNm,LastNm,Duty,Mobile,Tel,Fax,EMail,Nation,Taste,Education,Company,CTel,CAddress,CZip,Family,Version,id

将文件中的字段分割符用制表符代替,生成tmp.csv文件

sed 's/,/\t_/g' test.csv > tmp.csv

通过awk得到我们需要的字段,存到dealed.csv文件中

awk '{print $1,$5,$6,$7,$8,$32}' > dealed.csv

好的,现在有了处理好的文件dealed.csv,那么我们来把玩一番

先来看下男女比例

 awk '$3 ~ /_M/' dealed.csv | wc && awk '$3 ~ /_F/' dealed.csv | wc

输出

31179  187081 2792791
16085   96513 1455873

我们看到,是31179:16085,没有性别的忽略了,仅最小的这个文件来看,男比女大概是2:1的样子,额,说明了什么问题?看官自己发挥想象力吧

再来看看年份情况

awk '$4 ~ /^(_196)/' dealed.csv | wc && awk '$4 ~ /^(_197)/' dealed.csv | wc && awk '$4 ~ /^(_198)/' dealed.csv | wc && awk '$4 ~ /^(_199)/' dealed.csv | wc

输出

4885   29310  447630
9706   58239  884200
20533  123201 1831734
8100   48601  784771

明显看出80后占据开房主力地位!

再来看各年龄层女性占比

awk '$4 ~ /^(_196)/ && $3 ~ /_F/' dealed.csv | wc && awk '$4 ~ /^(_197)/ && $3 ~ /_F/' dealed.csv | wc && awk '$4 ~ /^(_198)/ && $3 ~ /_F/' dealed.csv | wc && awk '$4 ~ /^(_199)/ && $3 ~ /_F/' dealed.csv | wc

输出

   1359    8154  122638
   2922   17533  259771
   7124   42746  634798
   3736   22416  360216

擦,90后女生比例明显高了。

ok,这边先这样。

 

来看看awk 带有-f选项的用法,又能对开放记录做什么手术呢?

引入文件ald

{
if ($4 ~ /^(_199)/ && $3 ~ /_F/) $1 = "阿拉丁和"$1"开房了,今天是"$6
if ($1 ~ /阿拉丁/) print
}

然后awk -f之

awk -f ald dealed.csv | less

xx

我靠,楼主一下子和n个90后妹纸开房了,开个玩笑~

楼主表示,不会泄漏任何信息,也别向楼主提出任何查询请求,本文仅用于技术探讨,over。

 

CodeIgniter保留字

控制器

  • Controller
  • CI_Base
  • _ci_initialize
  • Default
  • index

函数

  • is_really_writable()
  • load_class()
  • get_config()
  • config_item()
  • show_error()
  • show_404()
  • log_message()
  • _exception_handler()
  • get_instance()

变量

  • $config
  • $mimes
  • $lang

常量

  • ENVIRONMENT
  • EXT
  • FCPATH
  • SELF
  • BASEPATH
  • APPPATH
  • CI_VERSION
  • FILE_READ_MODE
  • FILE_WRITE_MODE
  • DIR_READ_MODE
  • DIR_WRITE_MODE
  • FOPEN_READ
  • FOPEN_READ_WRITE
  • FOPEN_WRITE_CREATE_DESTRUCTIVE
  • FOPEN_READ_WRITE_CREATE_DESTRUCTIVE
  • FOPEN_WRITE_CREATE
  • FOPEN_READ_WRITE_CREATE
  • FOPEN_WRITE_CREATE_STRICT
  • FOPEN_READ_WRITE_CREATE_STRICT

Nginx,CodeIgniter,PATH_INFO

1.什么是PATH_INFO?

PATH_INFO是一个CGI 1.1的标准,经常用来做为传参载体.

例如www.coderaladdin.com/test.php,并且test.php这个文件存在.当服务器接收这样的请求www.coderaladdin.com/test.php/path/info,那么PATH_INFO的值就是/path/info.

2.Nginx中的PATH_INFO

ngxin中默认配置中式没有PATH_INFO的设置的,在默认配置下,接收到如上请求是则会报404,那么如何解决这个问题呢,网上有多种方法可以参考,nginx官方的方法是通过fastcgi_split_path_info 来配置PATH_INFO

fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

默认配置中的

location ~ .php$ {
    ……
}

要记得改成

location ~ .php {
    ……
}

3.CodeIgniter中的路由原理

具体路由原理不详述,只说在lnmp中CI能够正常使用rewrite的方法有二

  1. 如上所述,配置nginx支持PATH_INFO
  2. 在CI中修改/application/config/config.php,将
    $config['uri_protocol']	= 'AUTO';

    修改为

    $config['uri_protocol']	= 'REQUEST_URI';

     

原生PHP和Zend Framwork中使用SOAP做webservice

soap的两种实现方式:WSDL和Non-WSDL

1.non-wsdl模式利用php的soap扩展实现:

server

<?php
class HandleClass {
    public function test() {
        return '23434';
    }
}

//uri必填
$soap_server = new SoapServer(null, array('uri'=>'http://soap/','location'=>'http://localhost/soap/server.php'));
$soap_server->setClass('HandleClass');
$soap_server->handle();

client

<?php
//location和uri必填
$soap_client = new SoapClient(null, array('location'=>'http://localhost/soap/server.php','uri'=>'http://soap/'));
echo $soap_client->test();

output:

23434

2.wsdl利用php的soap扩展实现

server:

<?php
class service {
	public function HelloWorld() {
		return "Hello";
	}
}
$server = new SoapServer ('helloworld.wsdl');
$server->setClass ( "service" );
$server->handle ();

client:

<?php
$client = new SoapClient ( "helloworld.wsdl" );
echo $client->HelloWorld ();

wsdl:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/helloworld/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="helloworld" targetNamespace="http://www.example.org/helloworld/">
  <wsdl:types>
    <xsd:schema targetNamespace="http://www.example.org/helloworld/">
      <xsd:element name="HelloWorld">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="in" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="HelloWorldResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="out" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="HelloWorldRequest">

  </wsdl:message>
  <wsdl:message name="HelloWorldResponse">
    <wsdl:part name="HelloWorldReturn" type="xsd:string"/>
  </wsdl:message>
  <wsdl:portType name="helloworld">
    <wsdl:operation name="HelloWorld">
      <wsdl:input message="tns:HelloWorldRequest"/>
      <wsdl:output message="tns:HelloWorldResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="helloworldSOAP" type="tns:helloworld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="HelloWorld">
      <soap:operation soapAction="http://www.example.org/helloworld/HelloWorld"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="helloworld">
    <wsdl:port binding="tns:helloworldSOAP" name="helloworldSOAP">
      <soap:address location="http://localhost/soap/wsdlServer.php"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

output:

Hello

BTW,zendstudio 10中可以通过插件的 方式支持wsdl的图形化编辑,见下图QQ截图20130720164549

3.non-wsdl模式利用zend的soap组件实现

handle:

<?php
class Example_Manager {

	/**
	 * Returns list of all products in database
	 *
	 * @return array
	 */
	public function getProducts() {
		$db = Zend_Registry::get ( 'Zend_Db' );
		$sql = "SELECT * FROM products";
		return $db->fetchAll ( $sql );
	}

	/**
	 * Returns specified product in database
	 *
	 * @param integer $id        	
	 * @return array Exception
	 */
	public function getProduct($id) {
		if (! Zend_Validate::is ( $id, 'Int' )) {
			throw new Exception ( 'Invalid input' );
		}
		$db = Zend_Registry::get ( 'Zend_Db' );
		$sql = "SELECT * FROM products WHERE id = '$id'";
		$result = $db->fetchAll ( $sql );
		if (count ( $result ) != 1) {
			throw new Exception ( 'Invalid product ID: ' . $id );
		}
		return $result;
	}
}

 

server:

public function soapserverAction()
    {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	$server = new Zend_Soap_Server(null, array('uri' => 'http://zenddemo.com/index/soapserver', 'location'=> 'http://zenddemo.com/index/soapserver'));

    	$server->setClass('Example_Manager');

    	$server->handle();
    }

client:

public function soapclientAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);
    	$options = array(
    			'location' => 'http://zenddemo.com/index/soapserver',
    			'uri'      => 'http://zenddemo.com/index/soapserver'
    	);

    	try {
    		$client = new Zend_Soap_Client(null, $options);
    		$result = $client->getProducts();
    		print_r($result);
    	} catch (SoapFault $s) {
    		die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
    	} catch (Exception $e) {
    		die('ERROR: ' . $e->getMessage());
    	}
    }

 4.wsdl模式用zend的soap组件实现

handle:同上

server:

public function soapwsdlserverAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	$server = new Zend_Soap_AutoDiscover();
    	$server->setClass('Example_Manager');
    	$server->setUri('http://zenddemo.com/index/soapserver');
    	$server->handle();
    }

client:

public function soapclientAction() {
    	$this->getHelper('viewRenderer')->setNoRender(true);

    	try {
    		$client = new Zend_Soap_Client('http://zenddemo.com/index/soapwsdlserver');	
    		$result = $client->getProducts();
    		print_r($result);
    	} catch (SoapFault $s) {
    		die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
    	} catch (Exception $e) {
    		die('ERROR: ' . $e->getMessage());
    	}
    }

 

 

Little tips

1.昨天遇到的一个问题,session文件无法写入

原因:我在php.ini中设置了一个session路径,但是在windows下用的linux的正斜杠,一直以为windows能正确解析路径,因为我在apache中配虚拟主机的时候都是用的正斜杠,囧

 

2.svn的一个小技巧,当把错误代码提交到服务器时,想要回滚版本,show log->revert to this version(想要回滚到的版本)->commit

开源JS日历控件ESONCalendar的bug修复

Bug description:

在选择月份的日期数小于当前日期数时会跳到下月份,比如当前日期是1月30号,当选择2月时,会自动跳到3月,2月只有28或29天小于当前日期的30号

Code:

/*
 * @use:
 * <input type="text" name="riqi" id="Text1" size="31" style="margin:2px auto 2px auto;" value="2013-01-29">
 * <script type="text/javascript"> 
 *  ESONCalendar.bind("Text1");
 * </script>
 */
var _ESONCalendar = window.ESONCalendar = {
    hasFoot: true,
    weeks: "日一二三四五六",
    months: "一,二,三,四,五,六,七,八,九,十,十一,十二",
    start: 1900,
    end: 2050,
    color: {
        caption: "#A4B9D7",
        border: "#C0D0E8",
        tablebg: "#F6F6F6",
        selectedbg: "#FF9900",
        foot_co: "#003366",
        selectedco: "#ffffff"
    },
    dateBox: [],
    splitChar: "-",
    splitChar2: ":",
    hotInput: null,
    initli: false,
    init: function () {
        return this.addStyle().addUI().hide();
    },
    uanv_tool_CE: function (type, id, parent, className, HTML) {//SELECT, selMonth, _caption
		//console.log(type + '==' + id + '==' + parent + '==' + className + '==' + HTML)
        var obj = document.createElement(type.toUpperCase());
        id && (obj.id = id);
        className && (obj.className = className);
        HTML && (obj.innerHTML = HTML);
        parent || (parent = document.body);
        return parent.appendChild(obj);
    },
    uanv_tool_getWeek: function (date, i) {
        var tmp = new Date(date);
        tmp.setDate(i);
        return tmp.getDay();
    },
    uanv_tool_isIn: function (o, parent) {
        while (o != parent && o != document.body) {
            o = o.parentNode
        };
        return o != document.body;
    },
    onselect: function (d) {
        this.hotInput && (this.hotInput.value = d.y + this.splitChar + d.m + this.splitChar + d.d), this.hide()
    },
    addStyle: function () {
        var cssText = "#ESONCalendar_Win{background:" + this.color.caption + ";position:absolute;z-index:9999}";
        cssText += "#ESONCalendar_caption{padding:3px;background:" + this.color.caption + ";overflow:hidden;}";
        cssText += ".clear{clear:both}";
        cssText += "#selMonth{margin-right:5px;width:80px}";
        cssText += "#selYear{margin-right:3px;}";
        cssText += "#ESONCalendar_table{background:" + this.color.tablebg + ";border-collapse:collapse;border:1px solid " + this.color.border + "}";
        cssText += "#ESONCalendar_table th{border:1px " + this.color.border + " solid}";
        cssText += "#ESONCalendar_week{background:" + this.color.border + "}";
        cssText += "#ESONCalendar_week th{font-size:12px;width:18px;height:18px;}";
        cssText += "#dateBox{font:normal 12px /120% 'arial';}";
        cssText += "#dateBox th{font-weight:normal}";
        cssText += "#dateBox .unselected{cursor:pointer;background:" + this.color.tablebg + ";}";
        cssText += "#dateBox .sunday{cursor:pointer;background:" + this.color.tablebg + ";color:red}";
        cssText += "#dateBox .current,#dateBox .selected{cursor:pointer;background:" + this.color.selectedbg + ";color:" + this.color.selectedco + "}";
        cssText += "#ESONCalendar_foot{padding:2px 0 2px 0;line-height:130%;text-align:center;font-size:11px;color:" + this.color.foot_co + ";background:" + this.color.border + "}";
        cssText += "#ESONCalendar_Win iframe{position:absolute;z-index:-1;top:0;left:0}";
        var STYLE = document.createElement('style');
        STYLE.setAttribute("type", "text/css");
        STYLE.styleSheet && (STYLE.styleSheet.cssText = cssText) || STYLE.appendChild(document.createTextNode(cssText));
        document.getElementsByTagName('head')[0].appendChild(STYLE);
        return this;
    },
    addUI: function () {
        if (this.initli) {
            return;
        }
        this.Win = this.uanv_tool_CE("DIV", "ESONCalendar_Win");
        KillSelectIframe = this.uanv_tool_CE("IFRAME", false, this.Win);
        var _caption = this.uanv_tool_CE("DIV", "ESONCalendar_caption", this.Win);
        var selMonth = this.uanv_tool_CE("SELECT", "selMonth", _caption);
        var selYear = this.uanv_tool_CE("SELECT", "selYear", _caption);
        this.selMonth = selMonth;
        this.selYear = selYear;
        selMonth.onchange = selYear.onchange = function () {
            ESONCalendar.dateUp(new Date(selYear.value, selMonth.value, 1))
        };
        for (var i = 0; i < 12; i++) {
            var tmp = new Option(this.months.split(",")[i] + "月", i);
            selMonth.options.add(tmp);
        };
        for (var i = this.start; i < this.end; i++) {
            var tmp = new Option(i, i);
            selYear.options.add(tmp);
        };
        this.uanv_tool_CE("DIV", false, _caption, "clear");
        var table = this.uanv_tool_CE("TABLE", "ESONCalendar_table", this.Win);
        var tbody = this.uanv_tool_CE("TBODY", false, table);
        var tr = this.uanv_tool_CE("TR", "ESONCalendar_week", tbody);
        for (var i = 0; i < 7; i++) {
            var th = this.uanv_tool_CE("TH", false, tr, false, new String(this.weeks).charAt(i));
        }
        tbody = this.uanv_tool_CE("TBODY", "dateBox", table);
        for (var i = 0; i < 6; i++) {
            tr = this.uanv_tool_CE("TR", false, tbody);
            for (var j = 0; j < 7; j++) {
                var thisBox = this.uanv_tool_CE("TH", false, tr, false, "&nbsp;");
                this.dateBox[i * 7 + j] = thisBox;
            }
        };
        if (this.hasFoot) {
            this.foot = this.uanv_tool_CE("DIV", "ESONCalendar_foot", this.Win, false, this.footText);
        }
        KillSelectIframe.frameBorder = 0;
        KillSelectIframe.width = this.Win.offsetWidth;
        KillSelectIframe.height = this.Win.offsetHeight;
        document.onclick = document.body.onclick = function (e) {
            e || (e = window.event);
            var src = e.target || e.srcElement;
            var tmp = src.nodeName.toUpperCase();
            if (tmp == "HTML" || tmp == "BODY") {
                return ESONCalendar.hide();
            }
            if (src == ESONCalendar.hotInput || ESONCalendar.uanv_tool_isIn(src, ESONCalendar.Win)) {
                return;
            }
            ESONCalendar.hide();
        };
        this.initli = true;
        return this;
    },
    dateUp: function (date, first) {
        var space = this.uanv_tool_getWeek(date, 1);
        var m2d = 31, index = 1;
        this.y = date.getFullYear();
		this.m = date.getMonth() + 1;
		this.d = date.getDate();
        this.h = date.getHours();
        this.mi = date.getMinutes();
        this.s = date.getSeconds();
        this.selMonth.options[this.m - 1].selected = "selected";
        this.selYear.options[this.y - this.start].selected = "selected";
        var isRN = (this.y % 4 == 0 && this.y % 4 != 100 || this.y % 100 == 0 && this.y % 400 == 0);
        if (/-4|-6|-9|-11/.test("-" + this.m)) {
            m2d = 30
        };
        if (this.m == 2) {
            m2d = isRN ? 29 : 28
        };
        for (var i = 0; i < 42; i++) {
            var _this = this.dateBox[i];
            _this.isSunday = _this.className = _this.isInMonth = _this.onmouseover = _this.onmouseout = _this.onclick = null;
            if (i < space || i > (m2d + space - 1)) {
                _this.uanv_tool_isInMonth = false;
                _this.innerHTML = "&nbsp;";
                continue
            };
            _this.innerHTML = index++;
            _this.className = "unselected";
            _this.isInMonth = true;
            var week = this.uanv_tool_getWeek(date, _this.innerHTML);
            if (week == 0 || week == 6) {
                _this.className = "sunday";
                _this.isSunday = true;
            }
            if (first && (index - 1) == this.d) {
                _this.className = "selected";
            }
            _this.onmouseover = function () {
                if (this.className != "selected") this.className = "current"
            };
            _this.onmouseout = function () {
                if (this.className != "selected") this.className = this.isSunday ? "sunday" : "unselected"
            };
            _this.onclick = function () {
                var allD = ESONCalendar.dateBox;
                for (var i = 0; i < allD.length; i++) {
                    var _for = allD[i];
                    _for.className = "";
                    if (_for.isInMonth) {
                        _for.className = "unselected";
                    }
                    if (_for.isSunday) {
                        _for.className = "sunday";
                    }
                };
                this.className = "selected";
                ESONCalendar.d = this.innerHTML;
                ESONCalendar.onselect({
                        y: ESONCalendar.y,
                        m: ESONCalendar.m,
                        d: this.innerHTML,
                        h: ESONCalendar.h,
                        mi: ESONCalendar.mi,
                        s: ESONCalendar.s
                    });
            };
        };
        return this;
    },
    showTo: function (obj) {
        var oldObj = obj;
        for (var pos = {
                x: 0,
                y: 0
            }; obj; obj = obj.offsetParent) {
            pos.x += obj.offsetLeft;
            pos.y += obj.offsetTop
        };
        this.Win.style.left = pos.x + "px";
        this.Win.style.top = (pos.y + 2 + oldObj.offsetHeight) + "px";
        this.Win.style.display = "";
        return this;
    },
    bind: function (input) {
        if (!this.initli) {
            this.init();
        }
        "string" == typeof (input) && (input = document.getElementById(input));
        if (!input.type || input.type.toUpperCase() != "TEXT") {
            return this;
        }
        input.onfocus = function () {
            var dates = this.value.split(ESONCalendar.splitChar);
            var bindD = this.value.length > 0 ? new Date(dates[0], dates[1] - 1, dates[2]) : new Date();
            ESONCalendar.dateUp(bindD, true);
            ESONCalendar.showTo(ESONCalendar.hotInput = this);
        };
        return this;
    },
    hide: function () {
        this.Win.style.display = "none";
        return this
    },
    setInfo: function (v) {
        this.foot.innerHTML = v;
        return this
    }
};

 

高德地图API使用

记录下高德地图api使用中踩到的坑

踩坑代码:

var mapObj=new AMap.Map("div_gmap",{center:position});//创建地图实例
var bounds=mapObj.getBounds();//获取map实例的可是区域地理坐标实例

果断报错了:一个未定义的da方法

 

解决问题的代码:

var mapObj=new AMap.Map("div_gmap",{center:position});//创建地图实例
mapObj.plugin(["AMap.ToolBar"],function(){  
		//加载工具条  
		tool=new AMap.ToolBar({});  
		mapObj.addControl(tool); 
		var bounds = mapObj.getBounds();
})

将获取视窗地理坐标实例的代码放到plugin中来执行,应该是一个异步加载的原理,未深究。

 

nginx php 502 bad gateway

今天配centos6.3+nginx+php5.4.15(fpm),蛋碎了无数次,其中一个问题就是配PMA的时候,访问phpMyAdmin时,出现下面错误。

phpMyAdmin – Error

Cannot start session without errors, please check errors given in your PHP and/or webserver log file and configure your PHP installation properly.第一次打开提示,刷新提示:

502 bad gateway

查看nginx error log:

[error]  recv() failed (104: Connection reset by peer) while reading response header from upstream, client:, server: , request: “GET / HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “mysql.veryi.com”

查看php session.save_path的设置,默认是/var/lib/php/session。修改该目录nginx进程的用户有读写权限。问题解决。

参考

 

SVN分支与合并

1.创建分支的意义

创建分支的意义,比如我们在一个基础平台上进行开发,每个技术小组负责一个子项目,而基础平台也是有可能会继续更改的,这个时候,如果不创建分支,子项目之间会相互影响,影响最大的就是后期的测试和版本发布,子项目A已经结束,但测试却受到正在进行的子项目B的影响,测试通不过,就别说版本发布了。所以,我们需要从目前的项目(主干trunk)中创建分支(branch),隔离子项目间的相互影响。

2.svn创建分支原理

在svn中,创建分支,实际上就是一个版本拷贝(对应copy to…注意:绝不是简单在客户端上copy一个目录,而是svn仓库中copy,文件版本号会增加。),两边做任何修改发生的版本变化,是一套机制。举例:目前主干版本是100,分支版本是101,主干中增加一个文件,版本为102,分支中再增加一个文件,版本就为103了。两边的版本号是一套,不会重复。

3.svn创建分支的方法

TortoiseSVN:右键点击工程目录->TortoiseSVN->Branch/tag..菜单,From WC at Url自动为工程svn url,比如https://localhost:8443/svn/fbysss/prj1/trunk,to Url填写https://localhost:8443/svn/fbysss/prj1/branches/branch1。点OK按钮,分支就创建好了。

Subclipse:Team->Branch/tag..,跟上面类似.

SVN命令模式:svn copy trunk_path  branch_path  -m ‘描述’

举例:svn copy https://localhost:8443/svn/fbysss/prj1/trunk 

https://localhost:8443/svn/fbysss/prj1/branches/branch1 -m “第一个分支”

注意一点:trunk和branch不能互为子目录,否则就乱套了。

4.分支合并

1)从分支合并到主干

分支开发结束之后,往往需要合并回主干去测试、发布,但分支和主干可能有很多冲突的地方,在合并时经常需要手工解决。

被操作对象:主干

From主干的打出分支时的版本

To:分支的Head版本(最新版本)

 

怎么理解这个From和To呢?似乎跟我们的想当然不太一样:因为我们理解,把分支合并到主干,肯定是From分支,To主干。怎么搞反了呢?

实际上,Svn认为,我们要合并的,是从主干的某个版本开始,到分支的某个版本结束。两边的版本号实际上是一套系统,不会有重复。

2)从主干合并到分支

试想这样的情况:一个项目里面,要独立出来一个子项目,需要单独发布版本,用到了基础框架代码,而基础框架在主干中不断修改完善,这就需要从主干合并到分支。

被操作对象:分支

From:分支的第一个版本(最旧版本)

To:主干的Head版本(最新版本)

相当于从分支的第一个版本开始一直到主干最后一个版本结束合并之后,替换分支。

3)从分支合并到分支

有这样的需求:一个项目中有很多分支,这些分支需要分期上线,有多个工作并行,但每一期之间不能相互影响,这就可以打出几个tag(也是分支),从主干copy而来。其他主干根据排期分别合并到这些tag中来。比如有prjTag1和prjTag2,model1、model2需要合并到prjTag1中,model3、model4需要合并到prjTag2中。拿prjTag1举例:

在prjTag1的work copy中,merge

 

From主干的打出分支时的版本

To:分支的Head版本(最新版本)

注意:From不是本Tag的某个版本,而是之前主干打出分支时的版本,最终Merge到prjTag1的work copy,而prjTag1是找不到当初打分支时的版本的。

原文