转到正文

浪淘沙

静观己心,厚积薄发

同学说服务器上一个php文件不能正常访问了,直接显示了nginx的500页面了。ssh到服务器,开始debug之旅。

首先,查看nginx log,看到如下的log信息:

2017/04/13 15:42:20 [error] 14276#0: *102641755 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 182.129.141.222, server: yy1.bjshinesky.com, request: “POST /v1/useractivates.php HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”

这样的log,网上一搜,一模一样的问题一大堆。导致这条log的情况如下:

       php-fpm timeout直接导致php-fpm被kill再重启。同学这个肯定不是这个情况——访问问题url,直接就500错误页面了,根据不是timeout的问题导致的。为了安全期间,还是看了nginx.conf和php-fpm.conf,发现各种配置项都正常。排除。

下面各种猜测问题:

1、新建一个p.php 调用phpinfo()。访问,一切正常。 — 说明php-fpm执行正常

2、修改p.php 故意弄出语法错误。访问,不再是500错误,而且log可以显示具体的PHP错误信息。 — 说明日志已经记录了php错误信息。访问提问题url没有报php错误信息,并不是因为php语法错误

3、直接命令行执行问题php文件。直接报错:File size limit exceeded. —系统资源限制(猜测可能是因为操作了过大的文件,直接被系统限制了。)

跟踪代码发现,问题php文件里面有好多log write.除了这个,也就是是curl了。猜测应该是日志文件太大,导致打开日志文件的时候出现了问题。找到存放日志文件目录,执行命令’ll’查看目录文件信息。

-rw-r–r– 1 nobody nobody 2147483647 Apr 10 15:13 2017-04-10.log
-rw-r–r– 1 nobody nobody 2147483647 Apr 11 11:18 2017-04-11.log
-rw-r–r– 1 nobody nobody 2147483647 Apr 12 14:07 2017-04-12.log

嗯,文件大小为:2147483647 = 2^31 -1 。再次猜想,当日志文件大于这个数值的时候(32位的默认单文件最大2G),php-fpm被系统强制挂起。

测试猜想:

cp 2017-04-11.log 2017-04-11.log.bak   —备份

> 2017-04-11.log — 清空log文件

再次执行问题php文件,正常,浏览器访问,正常。

问题解决。

 

PS:

1、先上日志只记录必要消息,debug相关的信息要及时关掉;

2、线上写文件日志的时候,一定要控制日志文件的大小,不要不管文件大写,只管写log;

 

参考:

http://www.th7.cn/Program/php/201408/254237.shtml

http://blog.csdn.net/dc_726/article/details/11950189

http://www.jb51.net/article/38489.htm

http://blog.sina.com.cn/s/blog_4ae178ba0100z5a7.html

 

阅读全文

事件:

废话不多说。POST的数据被截断(并没有报内存不足错误),造成这种现象有2种原因:

1、php.ini 中 post_max_size (默认 2M)

2、php.ini 中max_input_vars 限制了(默认1000个键值对。如果post提交的键值对超过1000,多余的键值对就会被截断)

PS: max_input_vars 这个配置项使用ini_set进行设置不会生效,必须要修改php.ini之后 重新reload才会有效。

阅读全文

I have the name of a function in JavaScript as a string. How do I convert that into a function pointer so I can call it later?

Depending on the circumstances, I may need to pass various arguments into the method too.

Some of the functions may take the form of namespace.namespace.function(args[...]).

 

========

Don’t use eval unless you absolutely, positively have no other choice.

As has been mentioned, using something like this would be the best way to do it:

window["functionName"](arguments);

That, however, will not work with a namespace’d function:

window["My.Namespace.functionName"](arguments); // fail

This is how you would do that:

window["My"]["Namespace"]["functionName"](arguments); // succeeds

In order to make that easier and provide some flexibility, here is a convenience function:

function executeFunctionByName(functionName, context /*, args */) {
  var args = [].slice.call(arguments).splice(2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(this, args);
}

You would call it like so:

executeFunctionByName("My.Namespace.functionName", window, arguments);

Note, you can pass in whatever context you want, so this would do the same as above:

executeFunctionByName("Namespace.functionName", My, arguments);
阅读全文

eval executes a string containing code, e.g.

eval("var x = 'Hello from eval!';");
console.log(x);

eval raises several issues:

  1. Security: your string can be injected with other commands by third-party scripts or user input.
  2. Debugging: it’s difficult to debug errors — you have no line numbers or obvious points of failure.
  3. Optimization: the JavaScript interpreter cannot necessarily pre-compile the code because it could change. While interpreters have become increasingly efficient, it’ll almost certainly run slower than native code.

Unfortunately, eval is very powerful and it’s easy for less experienced developers to overuse the command.

Despite the warnings, eval still works — even in Strict Mode — but you can normally avoid it. In the past it was primarily used for de-serializing JSON strings but we now have the safer JSON.parse method.

However, what if we have a function name in a string, e.g.

// function we want to run
var fnstring = "runMe";

function runMe() {
	// do stuff
}

How do we execute the runMe() function without using eval? I recently encountered this situation when using the HTML5 History API; the pushState method won’t permit you to store a direct reference to a function so you need to define its name as a string. You could also face similar challenges using Web Workers or any other API where objects are serialized.

The simplest and safest execution-without-eval solution is a range of conditions, e.g.

// function we want to run
var fnstring = "runMe";

switch (fnstring) {
	case "functionX": functionX(); break;
	case "functionY": functionY(); break;
	case "functionZ": functionZ(); break;
	case "runMe": runMe(); break;
}

It’s safe, but fairly inefficient and painful to write if you have dozens of possible function calls.

A better solution is to use the window object which references the current window and all items within it. We can check whether fnstring is available as an object within window and run it if it’s a function, e.g.

// function we want to run
var fnstring = "runMe";

// find object
var fn = window[fnstring];

// is object a function?
if (typeof fn === "function") fn();

You can perform other checks if necessary to ensure the function has an expected name.

What if the function we want to call has parameters — perhaps stored in an array? No problem; we simply use the apply method:

// function name and parameters to pass
var fnstring = "runMe";
var fnparams = [1, 2, 3];

// find object
var fn = window[fnstring];

// is object a function?
if (typeof fn === "function") fn.apply(null, fnparams);

So that’s another reason to stop using eval. As a bonus, this solution is safer, less error prone, easier to debug and will normally execute faster. I hope it helps.

 

One could also use:
setTimeout(“runMe”,0);

if(‘$’ in window && typeof window[‘$’] == ‘function’) window[‘$’](document)

阅读全文

js有的时候会出现,将方法名称作为一个参数传递到方法中,然后再调用。这个时候,就有可能会出现问题。

场景一

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam(fname);">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
param("sssssss");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

这种情况,没有任何问题,可以直接调用。typeof  param 结果为 function

场景二

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
param("sssssss");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

和场景一唯一不同的就是参数使用引号包裹了下,就这么一点点差别,结果却是完全不同。typeof param 的结果为string .最终的运行结果为:TypeError: param is not a function。这样操作,js尝试运行的是param而不是param对应的值fname。

这个时候有同学就说,使用eval,eval将任何的string作为code来运行。

场景三

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
eval("param(\"sssssss\")");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

结果依然和场景二一样。这个时候会有同学说:“不对,不对,你的eval使用方法错了”。然后这个同学给出了TA自己eval方法的实现方式

场景四

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
eval(param + "(\"sssssss\")");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

运行,ok很好。正确执行了相应的方法,问题得到了解决。

大家都知道eval的功能异常的强大,强大到我们不敢、也不能随随便便使用它。那么我们能不能不适用eval方法的实现方式哪?大家开动脑筋,想了一会,这个时候有另外一个同学兴奋的说有了,可以使用setTimeout间接调用

场景五

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
setTimeout(param + "(\"ssssss\")",0);
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

运行结果很好。那么是否还有其他方法可以实现这个哪?大家又陷入了深思。。

“window,可以使用当前window对象。我们定义的所有元素都会包含在window对象里面。”  这个时候一个默默无闻的同学终于开口了。

场景六

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);
// find object
var fn = window[param];
// is object a function?
if (typeof fn === "function") fn("sssss");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

运行下,非常棒。

这个方法还可以优化下。

场景七

<html>
<head>
<title>js fucntion name as the paramter</title>
</head>
<body>

<input type="button" name="button" value="button" onclick="passParam('fname');">button content</button>
</body>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
function passParam(param) {
alert(typeof param);

<div class="post-message " dir="auto" data-role="message">

if(param in window && typeof window[param] == 'function') window[param]("sssss");
}
function fname(s) {
alert("fname:(" + s + ")");
}
</script>
</html>

不错不错。

还可以再优化,可以抽象出来

/**
 * 根据字符串类型的方法名 调用对应的js function
 * executeFunctionByName("My.Namespace.functionName", window, arguments);
 * executeFunctionByName("Namespace.functionName", My, arguments);
 *
 * @param functionName
 * @param context
 * @returns {*}
 */

var smvcJSUtil = {
    executeFunctionByName: function (functionName, context /*, args */){ //对调 functionName function
        var args = [].slice.call(arguments).splice(2);
        var namespaces = functionName.split(".");
        var func = namespaces.pop();
        for (var i = 0; i < namespaces.length; i++) {
            context = context[namespaces[i]];
        }
        return context[func].apply(this, args);
    },
    functionExistsByName: function(functionName) { //判断制定字符串是否为function
        return functionName in window && typeof window[functionName] == 'function'
    }
};

方法越来越好了。。我们原来的问题不但解决了,而且还因此学到了很多知识。

参考:

http://www.sitepoint.com/call-javascript-function-string-without-using-eval/

http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string

 

阅读全文

上次发布代码的时候 再某个model类里面发现了一段比较奇葩的代码,代码如下:

$req_arr['PosFlag'] = 0;//上生产要改成2

顿时就被这种写法弄得雷死了。这种各种环境不同的情况不应该使用配置项来处理吗?不错,程序猿是可以懒,大家也推荐程序猿懒,

但这种做法不是懒,是没有脑子。

说起来这个还想起来上次发现的一个问题。再模板文件里面写死链接地址(链接地址也是有平台差异的)。我也是无力吐槽了。

 

一句话,请谨记:所有平台差异都不应该hardcoding在代码里面,都必须写到配置里面。

还有一句,别特么动不动就写1,2,3这样的魔术数字,你特么注释都不加,鬼知道这些带别什么意思。

 

阅读全文

最近遇到了几个session无效的问题。总结起来有以下几点:

1、session_start       查看session 是否正确开启了 (php.ini 查看 session.auto_start 设置)

2、如果使用了session_set_cookie_params 方法 查看当前domain和设置的domain是否一致

3、php.ini 如果设置 session.save_handler = files  查看 session.save_path = “N;/path” 是否有写权限 (如果系统安装多套php环境的话更要注意这个问题)

4、php.ini 如果设置 session.use_cookies = 1  查看cookie是否可以正确使用(cookie中 PHPSESSIONID 是否正确生成)

5、php.ini 如果设置了 session.cookie_domain ,查看当前域名是否和该domain一致。

6、查看cookie是否正确设置(cookie domain和path是否和当前domain和path一致)。

基本上就这些问题。

阅读全文

咱们做WEB都知道COOKIE和SESSION这对好基友。他们2个总是如影相随。大部分人也是知道如果客户端禁用COOKIE(发送request的时候不发送COOKIE或者直接unset($_COOKIE)来模拟禁用COOKIE)SESSION还是可以用了。只需要通过GET或者POST的方式传递过来SESSIONID即可。具体的做法如下:


<?php
unset($_COOKIE);//禁用cookie
$sid = isset($_REQUEST['sid']) ? $_REQUEST['sid'] :'';
if ($sid) {//如果将sessionid传递了过来,先设置sessionid 然后 开启session PS:session_id方法必须在session_start()之前调用,否则无效
session_id($sid);
}
session_start();
$sid = session_id();

if (isset($_SESSION['content'])) {
echo 'get session:',$_SESSION['content'],'<br/>';
} else {
$_SESSION['content'] = 'content';
echo 'save session<br/>';
}
echo '<a href="./session.php?sid='.$sid.'">one more</a>';

阅读全文

file_put_contents  这个方法顾名思义就是将一个字符串写入到指定的文件。这个方法需要注意的是:在出现并发事件的时候,file_put_contents可能会出现写入文件失败的情况。直接上测试代码。

</p>
<p>&lt;?php </p>
<p>$index = isset($_GET['index']) ? $_GET['index'] : microtime(true);<br />
$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, FILE_APPEND); </p>
<p>if ($ret === false) {<br />
    echo index, ' file_put_contents failure';<br />
} else {<br />
    echo index, ' file_put_contents success';<br />
}</p>
<p>

使用 apache的ab直接做压力测试。

path-to-ab:  ab -n 1000 -c 50 http://local.test.me/file_put_contents.php

PS:意思为 总共访问http://local.test.me/file_put_contents.php这个脚本1000次,50并发同时执行。

最后的到得结果950左右行记录。 也就是说,会有50左右次写失败。

稍微修改代码,在file_put_contents 后面追加参数 LOCK_EX。最终代码如下:

</p>
<p>&lt;?php</p>
<p>$index = isset($_GET['index']) ? $_GET['index'] : microtime(true);<br />
//$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, FILE_APPEND); //直接这样有失败的情况</p>
<p>$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, LOCK_EX | FILE_APPEND);</p>
<p>if ($ret === false) {<br />
echo index, ' file_put_contents failure';<br />
} else {<br />
echo index, ' file_put_contents success';<br />
}</p>
<p>

再次ab压测,得出结果正常。1000次写入全部成功。

参数 LOCK_EX的意思 php manual 描述如下:Acquire an exclusive lock on the file while proceeding to the writing. (写入文件的时候,添加一个排他锁)。

 

阅读全文

PHP支持OOP编程,这大家都知道。但是PHP的继承和JAVA还是有点区别的。比较致命的一点就是:如果子类(ExtendsB)显示实现构造方法,那么在实例化ExtendsB的时候,系统并不会主动调用父类(ExtendsA)的构造方法

如果必须调用父类构造方法有2种方法:

1、子类(ExtendsB)中不实现构造方法(及时子类不要空实现构造方法)

2、自己手动调用父类构造方法(parent::__construct();)

直接上例子吧。

<?php
class ExtendsA {
    protected $c;

    public function ExtendsA(){
        $this->c = 10;
    }
}

class ExtendsB extends ExtendsA{
    //public function b(){} //这行解注释 就不会打印东西出来。因为ExtendsA构造没有被执行
    public function print_data(){
        echo $this->c;
    }
}

$b = new ExtendsB();
$b->print_data();

而JAVA代码就不是这样的。无论是否实现构造方法,再实例化子类的时候,系统都会递归调用父类构造方法。

public class ExtendsTestMain {

    public static void main(String args[]) {
        ExtendsTestB b = new ExtendsTestB();
        b.printData();
    }
}

class ExtendsTestA {

    protected int c;

    public ExtendsTestA() {
        c = 10;
    }
}

class ExtendsTestB extends ExtendsTestA {

    public ExtendsTestB() {

    }

    public void printData() {
        System.out.println(c);
    }
}

 

阅读全文