手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表分类:PHP

Editor.md 上传图片的注意事项

 一般情况下,editor.md的上传图片功能已经够用了,提供了两种方式:本地上传和跨域上传,方式也很简单,跨域上传的话,则需要加callbackUrl的地址。参考:http://www.ipandao.com/editor.md/examples/image-upload.html 和 http://www.ipandao.com/editor.md/examples/image-cross-domain-upload.html。

不过我的问题和上面的不一样,因为我使用了PHP开发框架,那么在正常开发的过程中,表单提交都有csrf的验证。editor.md却没有这个功能,在官方的issue里有人提出了,可以通过设置uploadUrl来加入get参数。

嗯,理论上这样也OK。然而我使用的是YII2,在实际使用中,这个办法无效,原因是:

PHP代码
  1. public function validateCsrfToken($token = null)  
  2. {  
  3.     $method = $this->getMethod();  
  4.     // only validate CSRF token on non-"safe" methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1  
  5.     if (!$this->enableCsrfValidation || in_array($method, ['GET''HEAD''OPTIONS'], true)) {  
  6.         return true;  
  7.     }  
  8.   
  9.     $trueToken = $this->loadCsrfToken();  
  10.   
  11.     if ($token !== null) {  
  12.         return $this->validateCsrfTokenInternal($token$trueToken);  
  13.     } else {  
  14.         return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)  
  15.             || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);  
  16.     }  
  17. }  

看最后两个判断,只判断了POST和HEADER中有Csrf的情况,没有判断GET参数里的情况,如果你的项目已经趋向于稳定,不再随便升级Yii的版本,你可以在$this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)加一行:

PHP代码
  1. || $this->validateCsrfTokenInternal($this->get($this->csrfParam),$trueToken)  

即,允许从GET参数中获取 csrf的值。

然而,很多时间我们都会手贱去composer update,所以这个方法有点不太敢使用。最终,还是决定修改editor.md的插件,在image-dialog.js中加入几行:

JavaScript代码
  1. if (settings.crossDomainUpload)  
  2. {  
  3.     action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;  
  4. }  
  5. //在上面的if代码后先加入csrfToken的值的获取   
  6. var csrfToken = $('meta[name="csrf-token"]').attr('content');  
  7. var csrfField = "";  
  8. if (csrfToken) {  
  9.    var csrfParam = $('meta[name="csrf-param"]').attr('content');  
  10.    csrfField = "<input type='hidden' name='" + csrfParam + "' value='" + csrfToken + "' />";  
  11. }  

然后在下面的dialogContent里加入csrfField的内容,使之 变成:

JavaScript代码
  1. var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action +"\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +  
  2.                         ( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +  
  3.                         "<label>" + imageLang.url + "</label>" +  
  4.                         "<input type=\"text\" data-url />" + (function(){  
  5.                             return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +  
  6.                                                                 "<input type=\"file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +  
  7.                                                                 csrfField +  
  8.                                                                 "<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +  
  9.                                                             "</div>" : "";  
  10.                         })() +  
  11.                         "<br/>" +  
  12.                         "<label>" + imageLang.alt + "</label>" +  
  13.                         "<input type=\"text\" value=\"" + selection + "\" data-alt />" +  
  14.                         "<br/>" +  
  15.                         "<label>" + imageLang.link + "</label>" +  
  16.                         "<input type=\"text\" value=\"http://\" data-link />" +  
  17.                         "<br/>" + csrfField +  
  18.                     ( (settings.imageUpload) ? "</form>" : "</div>");  

注意红字所在地方,其实就加了这个字段而已。再次提交图片上传的时候,不会再报400错误了。

 

 

wordpress 升级遇到问题

升级wordpress的时候遇到:Briefly unavailable for scheduled maintenance. Check back in a minute.

其实解决方法很简单,到wordpress的根目录下。删除 .maintenance 文件即可。
 

ThinkPHP group count

 如果用sql语句来写group by 再count,这样的sql太容易 了。但由于现在都是在用框架,反而这类sql变得难写了。最近在折腾一个用TP 3框架写的代码,原来代码里写的是:

PHP代码
  1. $count = D('Album')->table(T('albums AS a'))  
  2.                     ->join(T('union AS u') . ' ON u.id=a.union_id')  
  3.                     ->join(T('company AS c') . ' ON c.id=a.store_id')  
  4.                     ->join(T('photo AS p') . ' ON a.id=p.parent_id')  
  5.                     ->field('a.*,u.name AS union_name,c.name as store_name')  
  6.                     //     ->field('count(a.id)')  
  7.                     ->where($where)  
  8.                     ->group('a.id')  
  9.                     ->count();  

看起来好象没有问题,但事实上。出来的结果却并不是你想要的,这个count并不是你要的count,而是每个组的条数。当然你也可以用select()来查出数据,再count($count)一下,但如果数据量过大。这样会崩溃 的。

最终用这样的方法解决了:

PHP代码
  1. $numsQuery = D('Album')->table(T('albums AS a'))  
  2.                     ->join(T('union AS u') . ' ON u.id=a.union_id')  
  3.                     ->join(T('company AS c') . ' ON c.id=a.store_id')  
  4.                     ->join(T('photo AS p') . ' ON a.id=p.parent_id')  
  5.                     ->field('a.*,u.name AS union_name,c.name as store_name')  
  6.                     //     ->field('count(a.id)')  
  7.                     ->where($where)  
  8.                     ->group('a.id')  
  9.                     ->buildSql();  
  10. $nums = D()->table("{$numsQuery} as t")->count();  

算是曲线求国吧。

其实很多人在问这种问题了,但更多的人建议是直接写sql。我这种是不写sql的啦 ~

 

 

宁可错杀3000,不可放走一个

看到这个,应该明白了吧
 

 delete from sablog_comments where visible =0 and content REGEXP '^[0-9a-zA-Z]{6} ' 

 
定期执行一下吧。NND

composer引用本地git做为源库

PHP使用者大多对composer是又爱又恨,爱的是composer require后,很多类库不用去下载了,恨的是网速卡成翔,虽然国内有很多道友做了镜象,但对于bower库这些都还是整体更新。

那么,如何只利用composer的基本功能来为自己服务呢?composer的官网有介绍,只要在composer.json中加入几行代码就行了。。

JavaScript代码
  1. "repositories":[  
  2.        {  
  3.            "type":"git",  
  4.            "url":"/var/www/gouki/test/"  
  5.        },  
  6.    ]  

上面的代码中/var/www/gouki/test,是我的一个git库。也是按照composer的标准来建的。里面只有一个composer.json文件:

JavaScript代码
  1. {  
  2.     "name":"gouki/test",  
  3.     "description":"test",  
  4.     "authors":[  
  5.         {  
  6.             "name":"gouki",  
  7.             "email":"xxxx@qq.com"  
  8.         }  
  9.     ],  
  10.     "minimum-stability":"dev",  
  11.     "require":{},  
  12.     "autoload":{  
  13.         "psr-4":{  
  14.             "gouki\\test\\":"src/" 
  15.         } 
  16.     }, 
  17.     "extra":{ 
  18.         "branch-alias":{ 
  19.             "dev-master":"1.0.x-dev"  
  20.         }  
  21.     }  
  22. }  

src目录下的代码中使用的namespace就是gouki\test,然后在原项目的composer.json中再加入:

JavaScript代码
  1. "require":{  
  2.         "gouki/test":"dev-master"  
  3.     },  

最后,运行一下composer update,你会看到项目的根目录下多了vendor目录,同时,vendor目录下也会多一个gouki/test的目录,至此项目引入成功,如果还不放心,那就看一下:vendor/composer/autoload_psr4.php中有没有gouki/test。

之所以这么做,就是因为前文所说的速度,当然也有小团队的成本。比如写个类,就可以直接composer进行加载了。

问题就这么来了,如果放到线上去,那上面的

XML/HTML代码
  1. "repositories":[    
  2.        {    
  3.            "type":"git",    
  4.            "url":"/var/www/gouki/test/"    
  5.        },    
  6.    ]   
  7. 需要改为:  
  8. "repositories":[    
  9.        {    
  10.            "type":"git",    
  11.            "url":"http://xxxx.xxx.xxx/git"    
  12.        },    
  13.    ]     

如果该git是public的,则不需要任何处理,如果git是需要登录的,则需要在项目的根目录下(和composer.json平级的目录)增加一个auth.json,里面也就两三行代码

JavaScript代码
  1. {    
  2.     "http-basic":{    
  3.         "http://xxxx.xxx.xxx/git":{    
  4.             "username":"",    
  5.             "password":""    
  6.         }    
  7.     }    
  8. }    

当然如果你是ssh免登陆的git则另计。至此一个小小的自建composer源就已经完成。