Volt directory can't be written

上周开始在新公司工作,公司使用的是Phalcon框架。以前只是听说过这个名字….(此处省略1万字).
当我在使用git克隆项目代码到本地时,访问项目出现了此错误:

Volt directory can't be written

看到不能被写入,首先想到的是文件权限问题,但是,我是在windows下,哪里来的权限问题?!那是什么问题呢?Volt是Phalcon框架的模板引擎,会将views下的文件重新编译后放在cache目录下。再一看项目第一级文件结构,没有cache文件,会不会是放在app或其他目录下呢?还是来看配置文件吧。

app/config/config.php文件里找到了cache的位置:

'application' => array(
        'controllersDir' => APP_PATH . '/app/controllers/',
        'modelsDir'      => APP_PATH . '/app/models/',
        'migrationsDir'  => APP_PATH . '/app/migrations/',
        'viewsDir'       => APP_PATH . '/app/views/',
        'pluginsDir'     => APP_PATH . '/app/plugins/',
        'libraryDir'     => APP_PATH . '/app/library/',
        'cacheDir'       => APP_PATH . '/app/cache/',
        'baseUri'        => '/',
    )

所以,在app下建立一个cache文件夹,再次在浏览器刷新,项目可以正常访问了。

Phpstorm代码提示phalcon设置

Phalcon框架因为是以PHP扩展的形式存在,所以不同于其他的框架,安装完成后,IDE还并不能提示代码,这里就需要用到Developer Tools。该工具可在github上找到,**传送门**。

  1. 下载项目

使用git工具clone

git clone https://github.com/phalcon/phalcon-devtools.git
  1. 设置PhpStorm

在PhpStorm左边项目下面有个External Libraries,双击可弹出对话框,对话框里点击’+’,然后选择你的developer-devtools目录下ide下对应的版本。现在便有提示了。这种方式同时适用于Visual Studio Code.

  1. 另一种方式

在PhpStorm插件里直接搜索phalcon,有一个autocomplete插件,安装后即可.

JavaScript数组转字符串另类方法

通常,当我们想将一个数组,如*[‘hello’,’world’]*转换为字符串的话,会使用join方法将其连接为一个字符串。前两天在看书的时候,学到了新的方法,虽然不是什么高级技巧,但是,也在此记录一下,说明自己以前没有去思考过。

  • 方法一,使用toString方法:
var a = ['hello','world'];
console.log(a.toString()); //hello,word
  • 方法二,使用强制类型转换:
var a = ['hello','world'];
console.log(String(a));

但是,需要注意的是,这里的两个方法只能以逗号将其连接,如果要以其他的方式,还是需要使用join方法。

ES6之Object.is

当你想比较两个值是否相等时,你可能会用相等运算符“==”或“===”,这两者的区别在于后者会增加类型的比较,虽然这样,有时依然不能够准确的比较.+0 === -0 返回true, 另外,NaN === NaN 得到的是false,这需要使用isNaN来检测NaN属性。

ECMAScript6引入了Object.is()来弥补遗留的这个问题。这个方法接收两个参数并且如果值相等返回true。两个参数在类型和值一样时会被判为相等。大多数情况下,Object.is()和”===”是一样的,不同的是使用Object.is()对+0和-0比较,返回false,而NaN返回true。下面是一些例子:

console.log(+0 == -0);              // true
console.log(+0 === -0);             // true
console.log(Object.is(+0, -0));     // false

console.log(NaN == NaN);            // false
console.log(NaN === NaN);           // false
console.log(Object.is(NaN, NaN));   // true

console.log(5 == 5);                // true
console.log(5 == "5");              // true
console.log(5 === 5);               // true
console.log(5 === "5");             // false
console.log(Object.is(5, 5));       // true
console.log(Object.is(5, "5"));     // false

JavaScript参数默认值(ES6新方法)

在之前,我有写过两篇关于JavaScript参数赋默认值和变量默认值的文章,今天又来谈谈JavaScript的默认参数。你不要问我,就一个默认参数还有什么好说的?我们都知道,JavaScript以ECMAScript为标准,而在今年6月17号,ECMAScript发布了新的版本,官方叫作ECMAScript 2015,但通常大家称其为ECMAScript 6或者 ES6。而我今天要说的就是这个新版本里的默认参数。在ES 6里,函数可以初始化参数附带的默认值,如果这个参数没有传值或传入一个undefined。简单的说就和很多其他语言一样可以这样写:

function  defaultValue(a,b=3){
    return a+b;
}

var val1 = defaultValue(3);   //val=6
var val2 = defaultValue(3,undefined);  //val = 6

在以前,这样写就是错误的,那么现在,当你在调用这个函数时,只传值给a,或者b传入undefined,b的值都为3。说到以前,那我在如何给JavaScript参数赋默认值中有说到利用arguments对象,这种方法在定义函数时,只需声明必填参数即可。还有一种方法是利用typeof作判断来赋默认值,如下:

function typeofSetDefaultValue(a,b){ b = typeof b !== 'undefined' ? b : 1; return a+b; }

相对于这两种方法,ES 6的新特性确实带来极大方便。但是,缺点就是,现在的主流浏览器还不支持。嘿,浏览器虽然暂时还不支持,也别表现出悲观,来点更兴奋的!你可以将一个函数当作默认值赋值给另一个函数的参数,如:

function funcToBeDefaultValue(a = surprise()){ return a; } function surprise(){ return 'surprise'; }

感觉被玩坏了?还有更会玩的。你还可以将它的邻居赋值给它:

function laterToDefaultValue(a,b = a + ' ',c = b + "world"){ return c; } var str = laterToDefaultValue('hello'); //str = "hello world";

更多关于JavaScript默认值信息请看这里:

  1. Default parameters
  2. parameter_default_value

JavaScript中innerText和textContent的区别

innerTexttextContent两个属性都用于得到文本文字,一直以来以为他俩没有分别,可是今天在本地做好的项目,部署到服务器后,我用Firefox浏览时,发现出错了,而控制台的错误是undefined,这就让我纳闷了。于是,通过google一番,才知道原来这两个还是有分别的。主要有3点,这里有对textContent的详细介绍。这里只说下不同。

Internet Explore引入了element.innerText,用途大体相同但是一下几个不同点:

  • textContent能得到所有元素内容,包括script和style元素。但是,IE独有属性innerText不可以。
  • innerText受style影响不会返回隐藏的文本,而textContent不会
  • 由于innerText受CSS样式影响,会产生一个回流,而textContent不会

另外,还需注意的是,在stackoverflow上有人提到,虽然innerText是IE独有属性,主流浏览器都支持,除了Firefox,而IE也是唯一一个不支持textContent的浏览器。这就解释了为什么我的项目在本地正常,而到了服务器就出问题了。但是,我们不能要求用户去使用某一种浏览器,那么该如何解决呢?

  • 使用jquery是最好的,最简便的。
  • 做一个兼容判断,代码如下:
function getText(elem){
     if(typeof elem.textContent != 'undefined'){
        return elem.textContent;
    }else{
        return elem.innerText;
    }
}

如何使用ajax实现异步上传文件(译文)

原文: http://www.sitepoint.com/html5-ajax-file-upload/

在之前我的文章里,我们讨论了怎么使用HTML5的拖拽功能和使用HTML5和Javascript操作文件。现在我们有一些文件将要上传到服务器。这个进程将在后台异步进行,因此用户可以在页面上做其他的事情。

The HTML

再次检查HTML表单:

<form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>HTML File Upload</legend>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
<div>
    <label for="fileselect">Files to upload:</label>
    <input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
    <div id="filedrag">or drop files here</div>
</div>
<div id="submitbutton">
    <button type="submit">Upload Files</button>
</div>
</fieldset>
</form>

我们将把文件上传至upload.phpPHP文件,这个页面将在用户点击上传文件后,处理AJAX上传请求和表单POST提交。
Javascript能够保证仅上传小于300,000Bjpg图片

The Javascript

首先,我们从新的一行创建一个函数FileSelectHandler,用于有文件被选择或者放入时调用。要遍历文件我们调用另一个函数UploadFile

// file selection
function FileSelectHandler(e) {

    // cancel event and hover styling
    FileDragHover(e);

    // fetch FileList object
    var files = e.target.files || e.dataTransfer.files;

    // process all File objects
    for (var i = 0, f; f = files[i]; i++) {
        ParseFile(f);
        UploadFile(f);
    }

}

文件上传需要XMLHttpRequest2对象,这个对象在FireFoxchrome中支持(译者注:这篇文章发表于2012年,当前各个浏览器的支持请看这里)。在我们调起Ajax之前,我们要确定upload方法存在并且有一个小于MAX_FILE_SIZE值的JPG图片

// upload JPEG files
function UploadFile(file) {

    var xhr = new XMLHttpRequest();
    if (xhr.upload && file.type == "image/jpeg" && file.size <= $id("MAX_FILE_SIZE").value) {
        // start upload
        xhr.open("POST", $id("upload").action, true);
        xhr.setRequestHeader("X_FILENAME", file.name);
        xhr.send(file);

    }

}

The PHP

<?php
$fn = (isset($_SERVER['HTTP_X_FILENAME']) ? $_SERVER['HTTP_X_FILENAME'] : false);
if ($fn) {

    // AJAX call
    file_put_contents(
        'uploads/' . $fn,
        file_get_contents('php://input')
    );
    echo "$fn uploaded";
    exit();
    
}else {

    // form submit
    $files = $_FILES['fileselect'];

    foreach ($files['error'] as $id => $err) {
        if ($err == UPLOAD_ERR_OK) {
            $fn = $files['name'][$id];
            move_uploaded_file(
                $files['tmp_name'][$id],
                'uploads/' . $fn
            );
            echo "<p>File $fn uploaded.</p>";
        }
    }

}

如何给JavaScript中函数的参数添加默认值

前段时间在写js代码时,有个地方需要给函数的参数赋默认值.于是,我毫不犹豫地在参数后面直接给了值,如:

function sum(a,b=2) {}

*ES6已支持上面的语法

因为平时写PHP代码时都是这样,说实话以前还真没有给js参数赋过默认值,但是一写出来就报错了.不用说,肯定是js不能这样使.于是上网查找了 一番,终于明白在js里给参数默认值,可以这样:

function sum(a){
    var b = arguments[1]?arguments[1]:2;
}

马上写了个测试试试,还真可以.为什么可以这样写呢?原因是js在编译时会把参数放入arguments这个数组里面,这让我想起了PHP里的func_get_args().但是,在一想,有问题啊!

是什么问题呢?js里面在作真假判断时,遇上undefined,null,0,''等这些情况时,是会返回假的,那么在这里,如果我调用这个函数,给b的值为零的话,那它不是会用默认值?情况真的是这样吗?试一试不就知道.

function sum(a){

var b = arguments[1]?arguments[1]:2;

alert(a+b);

}

sum(1,0);

结果,得到的还真是3,看来在使用的时候还需要注意一下啊.