开发一个博客显然离不开一个给力的编辑器,虽然我手痒写了个博客,但是写一个编辑器还是饶了我吧。鉴于百度的UEditor功能强大,可定制,文档 全,所以就决定是UEditor了。但我最终是要把博客架在新浪的SAE上,而新浪把本地文件的IO操作禁止了,使得UEdiotr的附件、图片上传和在 线涂鸦功能都不可用了。好在新浪提供了Storage来支持文件上传,下面我们就利用SAE的Storage对UEditor进行简单的hack。
文件上传修改
首先我们在Storage中创建一个名为"upload"的domain。
我用的UEditor版本是最新的1.2.3.0 PHP版本,在这个版本中,官方提供的PHP上传功能都统一通过调用 ueditor/php/Uploader.class.php 里的Uploader来实现,这样就更好改了。
在构造函数中我们看到upFile这个函数被调用来实现上传。首先,我们解决普通文件的上传,注意到upFile里面的这部分代码:
$this->fullName = $this->getFolder() . '/' . $this->getName();
if ( $this->stateInfo == $this->stateMap[ 0 ] ) {
if (!move_uploaded_file($file[ "tmp_name" ],$this->fullName)) {
$this->stateInfo = $this->getStateInfo( "MOVE" );
}
}
嗯,显然move_upload_file是不能用了,SAE提供了SaeStorage这个类来执行用户文件的存储管理,说明文档戳这里。
把代码改成下面这个样子:
$this->fullName = $this->getFolder() . '/' . $this->getName();
if ( $this->stateInfo == $this->stateMap[ 0 ] ) {
if(!defined('SAE_TMP_PATH')){
if ( !move_uploaded_file( $file[ "tmp_name" ] , $this->fullName ) ) {
$this->stateInfo = $this->getStateInfo( "MOVE" );
}
}
else{
$st=new SaeStorage();
$url=$st->upload('upload',$this->fullName, $file[ "tmp_name" ]);
if(!$url){
$this->stateInfo = $this->getStateInfo( "MOVE" );
}
else{
$this->fullName=$url;
}
}
}
SAE_TMP_PATH是SAE平台上自动定义的常量,我们用它来判定是否是在SAE上(因为还要兼容其他开发环境),如果在SAE上,生成一个 SaeStorage对象,调用upload这个API,第一个参数是在SAE的Storage里创建的Domain,第二个参数是保存的文件名(可以包 含目录,如果目录不存在,Storage会自动创建),第三个参数则是文件的临时名。当图片上传成功后会返回图片的URL,我们直接 令$this->fullName=$url;这样程序就能返回图片的完整地址给UEditor了。但是好像还有点问题。。。
上面代码的第一行调用了getFolder,代码如下:
private function getFolder()
{
$pathStr = $this->config[ "savePath" ];
if ( strrchr( $pathStr , "/" ) != "/" ) {
$pathStr .= "/";
}
$pathStr .= date( "Ymd" );
if ( !file_exists( $pathStr ) ) {
if ( !mkdir( $pathStr , 0777 , true ) ) {
return false;
}
}
return $pathStr;
}
似乎mkdir在SAE上不能用,反正Storage会自动帮我们创建目录,所以把这部分搞掉:
private function getFolder()
{
$pathStr = $this->config[ "savePath" ];
if ( strrchr( $pathStr , "/" ) != "/" ) {
$pathStr .= "/";
}
$pathStr .= date( "Ymd" );
if(!defined('SAE_TMP_PATH'))
{
if ( !file_exists( $pathStr ) ) {
if ( !mkdir( $pathStr , 0777 , true ) ) {
return false;
}
}
}
return $pathStr;
}
现在我们传个文档试试,文档成功地传上去了,在Storage里面也能看到上传的文件,但是在编辑器里面无法下载却裂了。看看链接的地址,原来 UEditor给我们的地址自动加上了修正地址。在editor_config.js中把所有的图片修正地址都改成""(本地测试的时候记得把URL改成 绝对路径)清除缓存刷新,重试,成功。
文件上传的修改完成。
在线涂鸦修改
由于在线涂鸦也需要保存图片到本地,所以这部分也要改一下。在线涂鸦的处理页面是scrawlUp.php,里面同样调用了调用Uploader来处理 文件的上传,不同的是,涂鸦上传采用了base64编码模式,Uploader调用base64ToImage来完成图片的保存。打开 Uploader.class.php,定位到下面的代码:
/**
* 处理base64编码的图片上传
* @param $base64Data
* @return mixed
*/
private function base64ToImage( $base64Data )
{
$img = base64_decode( $base64Data );
$this->fileName = time() . rand( 1 , 10000 ) . ".png";
$this->fullName = $this->getFolder() . '/' . $this->fileName;
if ( !file_put_contents( $this->fullName , $img ) ) {
$this->stateInfo = $this->getStateInfo( "IO" );
return;
}
$this->oriName = "";
$this->fileSize = strlen( $img );
$this->fileType = ".png";
}
file_put_content是不能用了,Storage提供了write这个API,改成下面的代码:
private function base64ToImage( $base64Data )
{
$img = base64_decode( $base64Data );
$this->fileName = "img".time() . rand( 1 , 10000 ) . ".png";
$this->fullName = $this->getFolder() . '/' . $this->fileName;
if(!defined('SAE_TMP_PATH')){
if ( !file_put_contents( $this->fullName , $img ) ) {
$this->stateInfo = $this->getStateInfo( "IO" );
return;
}
}
else{
$st=new SaeStorage(SAE_ACCESSKEY,SAE_SECRETKEY);
$url=$st->write('upload',$this->fullName,$img);
if(!$url){
$this->stateInfo = $this->getStateInfo( "IO" );
return;
}
else{
$this->fullName=$url;
}
}
$this->oriName = "";
$this->fileSize = strlen( $img );
$this->fileType = ".png";
}
在线涂鸦部分的代码修改完成。
图片管理
由于本地图片上传和附件上传方式一样,所以修改完附件上传代码,图片上传也能用了。但是图片的管理部分还是用不了,下面我们就对图片管理部分代码进行修改。
打开imageManager.php这个文件,注意到下面这段代码:
if ( $action == "get" ) {
$files = getfiles( $path );
if ( !$files ) return;
rsort($files,SORT_STRING);
$str = "";
foreach ( $files as $file ) {
$str .= $file . "ue_separate_ue";
}
echo $str;
}
程序通过调用递归函数getfiles来完成图片文件的查找,但是我们的文件都存储在Storage中,所以这部分getfiles对我们来说无用。Storage提供一个很方便的函数getList.
getList(string $domain, [string $prefix = NULL], [int $limit = 10], [int $offset = 0])
第一个参数是Storage的domain,第二个是路径前缀可以用来指定目录或者筛选文件,默认为NULL,第三个是返回条数,第四个是偏移量。将上面的代码改成:
$path = 'upload/'; //最好使用缩略图地址,否则当网速慢时可能会造成严重的延时
$action = htmlspecialchars( $_POST[ "action" ] );
if ( $action == "get" ) {
if(!defined('SAE_TMP_PATH'))
{
$files = getfiles( $path );
if ( !$files ) return;
rsort($files,SORT_STRING);
$str = "";
foreach ( $files as $file ) {
$str .= $file . "ue_separate_ue";
}
echo $str;
}
else
{
$st=new SaeStorage();
$num=0;
while($ret = $st->getList("upload", NULL, 100, $num )){
foreach($ret as $file) {
if ( preg_match( "/\.(gif|jpeg|jpg|png|bmp)$/i" , $file ) )
echo $st->getUrl('upload',$file). "ue_separate_ue";
$num++;
}
}
}
}
至此,图片管理部分修改完成。
此外还有远程图片抓取getRemoteImage.php,具体修改方法参照在线涂鸦的修改,UEditor到SAE的移植基本完工。