├── .gitignore ├── README.md ├── filesystem └── upyun.php ├── images └── upyun_icon.png ├── includes ├── bootstrap_compatible.php └── hacklogra_upyun.class.php ├── languages ├── hacklog-remote-attachment-zh_CN.mo └── hacklog-remote-attachment-zh_CN.po ├── loader.php ├── screenshot-1.png ├── screenshot-2.png ├── upload.php └── vendor └── upyun.class.php /.gitignore: -------------------------------------------------------------------------------- 1 | .htaccess 2 | wp-config.php 3 | wp-content/uploads/ 4 | wp-content/blogs.dir/ 5 | wp-content/upgrade/ 6 | wp-content/backup-db/ 7 | wp-content/advanced-cache.php 8 | wp-content/wp-cache-config.php 9 | sitemap.xml 10 | *.log 11 | wp-content/cache/ 12 | wp-content/backups/ 13 | sitemap.xml.gz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wordpress-plugin-for-UPYUN 2 | 3 | ##WordPress插件信息 4 | 5 | ### Hacklog Remote Attachment Upyun 6 | 7 | ------------------------------------------------------------ 8 | 9 | * Contributors: ihacklog 10 | * Donate link: http://ihacklog.com/donate 11 | * Tags: attachment,manager,admin,images,thumbnail,ftp,remote 12 | * Requires at least: 3.3 13 | * Tested up to: 4.6.1 14 | * Stable tag: 1.5.1 15 | 16 | ------------------------------------------------------------ 17 | 此插件用于为你的WP博客添加Upyun附件上传支持。 18 | 可以与WordPress无缝结合,通过WordPress上传图片和文件到upyun, 支持大文件上传(需要开启表单 API)和防盗链功能。 19 | 有任何问题,欢迎大家提交issue: 20 | 21 | github: 22 | https://github.com/ihacklog/hacklog-remote-attachment-upyun/issues 23 | 24 | Adds remote attachments support for your WordPress blog. 25 | 26 | ------------------------------------------------------------ 27 | 28 | ### Description 29 | Features: Adds remote attachments support for your WordPress blog. 30 | 31 | 此插件用于为你的WP博客添加Upyun附件上传支持。 32 | 33 | 可以与WordPress无缝结合,通过WordPress上传图片和文件到upyun, 支持大文件上传(需要开启表单 API)和防盗链功能。 34 | 35 | * 支持上传文件到upyun服务器(图片、其它附件等) 36 | * 支持同步删除(在WP后台媒体管理“删除”附件后,upyun服务器中的文件也随之删除) 37 | * @TODO 增加图片编辑功能 38 | * @TODO 优化防盗链功能 39 | 40 | * 1.1.0 增加与水印插件的兼容性,使上传到远程服务器的图片同样可以加上水印 41 | * 1.2.0 增加重复文件检测,避免同名文件被覆盖。更新和完善了帮助信息。 42 | * 1.2.1 修正在后台上传主题或插件时的bug. 43 | * 1.2.7 增加三种http数据发送方式支持远程附件(curl,fsockopen,streams),方便没有curl扩展支持的朋友. 44 | * 1.2.8 增加对xmlrpc支持(支持通过Windows Live Writer 上传图片时自动上传到Upyun服务器) 45 | * 1.2.9 修复Windows Live Writer 上传图片时url不正确的bug 46 | * 1.3.0 修复首次使用插件时,又拍云空间使用量为0时显示“测试连接失败”的bug.增加更详细的错误信息提示。 47 | * 1.4.0 增加form API上传支持,可上传100MB以内大小的文件(又拍云form API目前最大只支持100MB) 48 | * 1.4.2 增加空间TOKEN防盗链功能支持 49 | * 1.4.3 修复同一地方多处调用url时重复签名的bug 50 | * 1.4.4 修复点击Tools区的链接时,提示“没有权限”的BUG. 51 | * 1.4.5 更改url生成方式,避免因插件目录名称不同而导致404错误。增加对WP 3.9.1支持。修改对WP_http的调用方式。 52 | * 1.4.6 修复在高版本WP中打开插件表单API上传页面时报错的bug.修复默认表单API超时时间未设置时导致无法使用表单API上传的bug. 53 | * 1.5.0 编辑图片功能已经支持! 54 | * 1.5.1 fix #18 修复一个warning提示. (thanks to [GeorgeYan](https://github.com/ihacklog/hacklog-remote-attachment-upyun/issues/18)) 55 | * 1.5.2 增加wp 4.6.1 支持,使用upyun 最新sdk 56 | * 1.5.3 修复使用form api时一个php警告(form api上传时不应用重复应用本插件的非form api hook). 57 | 优化代码和修复若干bug. 移除无用的crypt类.此次更新,需要重新填写一次密码. 58 | 59 | 更多信息请访问[插件主页](http://ihacklog.com/?p=5001 "plugin homepage") 获取关于插件的更多信息,使用技巧等. 60 | [安装指导](http://ihacklog.com/?p=4993 "安装指导") 61 | 62 | ====================================================================================== 63 | 64 | For MORE information,please visit the [plugin homepage](http://ihacklog.com/?p=5204 "plugin homepage") for any questions about the plugin. 65 | 66 | [installation guide](http://ihacklog.com/?p=4993 "installation guide") 67 | 68 | * version 1.1.0 added compatibility with watermark plugins 69 | * version 1.2.0 added duplicated file checking,so that the existed remote files will not be overwrote. 70 | * version 1.2.1 fixed the bug when uploading new theme or plugin this plugin may cause it to fail. 71 | 72 | ### Installation 73 | 74 | 1. Upload the whole fold `hacklog-remote-attachment` to the `/wp-content/plugins/` directory 75 | 2. Activate the plugin through the 'Plugins' menu in WordPress 76 | 3. Configure the plugin via `Settings` -> `Hacklog Remote Attachment` menu and it's OK now,you can upload attachments(iamges,videos,audio,etc.) to the remote FTP server. 77 | 4. If your have moved all your local server files to remote server,then you can `UPDATE THE DATABASE` so that all your attachments URLs will be OK. 78 | You can visit [plugin homepage](http://ihacklog.com/?p=5001 "plugin homepage") for detailed installation guide. 79 | 80 | ### Screenshots 81 | 82 | 83 | ![截图1](/ihacklog/Wordpress-plugin-for-UPYUN/raw/master/screenshot-1.png "截图1") 84 | 85 | 86 | 87 | ![截图2](/ihacklog/Wordpress-plugin-for-UPYUN/raw/master/screenshot-2.png "截图2") 88 | 89 | 90 | 91 | ### Frequently Asked Questions 92 | see 93 | [Hacklog Remote Attachment FAQ](http://ihacklog.com/?p=5001 "Hacklog Remote Attachment FAQ") 94 | 95 | 96 | ### Upgrade Notice 97 | #### 1.4.x upgrade to 1.4.2 98 | 增加空间TOKEN防盗链功能支持 99 | 100 | #### 1.3.0 upgrade to 1.4.0 101 | 如果要使用**表单 API 功能**,注意在又拍云空间管理里面开启表单 API功能,并在插件后台选项中更新表单 API密匙. 102 | 103 | 104 | ### Changelog 105 | 106 | ### 1.4.3 107 | * fixed: the bug that say "you have no permission to do this" when click the 108 | link in Tools area. 109 | 110 | ### 1.4.3 111 | * fixed: the bug that duplicated sign the same url. 112 | 113 | ### 1.4.2 114 | * added: TOKEN based anti-leeching feature support. 115 | 116 | #### 1.4.1 117 | * added: HTML5 file info detect. 118 | 119 | #### 1.4.0 120 | * added: form API uploading support. 121 | 122 | #### 1.3.0 123 | * fixed: the bug that say "Connection failed" when the bucket is empty in the first time use this plugin. 124 | * improved: get verbose error message displayed. 125 | 126 | #### 1.2.9 127 | * fixed: Windows Live Writer file uploading bug(url incorrect). 128 | 129 | #### 1.2.8 130 | * added: xmlrpc support (when use Windows Live Writer or other client via xmlrpc upload attahcment,the attachment will auto uploaded to remote FTP server ) 131 | 132 | #### 1.2.7 133 | * added: curl,fsockopen,streams support for http communication. 134 | 135 | #### 1.2.6 136 | * added: duplicated thumbnail filename (this things may happen when crop is TRUE) 137 | 138 | #### 1.2.5 139 | * changed: use simple xor cypher instead of using blow_fish 140 | 141 | #### 1.2.4 142 | * fixe: curl connection timeout will return '',change the message to more detailed one[class UpYun]. 143 | 144 | #### 1.2.3 145 | * changed: load_textdomain param 3 uses basename(dirname()) instead of plugin_basename 146 | * fixed: trim spaces on options 147 | * improved: Prevent direct access to files 148 | * changed: uses upyun HTTP REST API to create and delete directory,files 149 | * improved: protect your API password with the strong blowfish cypher. 150 | * improved: the plugin settings page can show you the space useage of your remote bucket. 151 | 152 | #### 1.2.2 153 | * ported from Hacklog Remote Attachment 154 | -------------------------------------------------------------------------------- /filesystem/upyun.php: -------------------------------------------------------------------------------- 1 | errors = new WP_Error(); 42 | $this->check_param ($bucketname, $username, $password, $endpoint, $timeout); 43 | parent::__construct($bucketname, $username, $password, $endpoint, $timeout); 44 | 45 | } 46 | 47 | /** 48 | * @param $form_api_params 49 | */ 50 | public function set_form_api_params($form_api_params) { 51 | if (!empty($form_api_params['form_api_secret'])) { 52 | $this->form_api_secret = $form_api_params['form_api_secret']; 53 | } 54 | if (!empty($form_api_params['anti_leech_token'])) { 55 | $this->anti_leech_token = $form_api_params['anti_leech_token']; 56 | } 57 | if (!empty($form_api_params['form_api_allowed_ext'])) { 58 | $this->form_api_allowed_ext = $form_api_params['form_api_allowed_ext']; 59 | } 60 | //form_api_content_max_length 61 | if (!empty($form_api_params['form_api_content_max_length'])) { 62 | $this->form_api_content_max_length = 1024 * 1024 * $form_api_params['form_api_content_max_length']; 63 | } 64 | if (!empty($form_api_params['form_api_timeout'])) { 65 | $this->form_api_timeout = $form_api_params['form_api_timeout']; 66 | } 67 | if (!empty($form_api_params['anti_leech_timeout'])) { 68 | $this->anti_leech_timeout = $form_api_params['anti_leech_timeout']; 69 | } 70 | } 71 | 72 | 73 | /** 74 | * check the needed param 75 | * @param $bucketname 76 | * @param $username 77 | * @param $password 78 | * @param $endpoint 79 | * @param $timeout 80 | */ 81 | public function check_param($bucketname, $username, $password, $endpoint, $timeout) { 82 | if (empty($endpoint)) 83 | { 84 | $this->errors->add ( 'empty_api_domain', __ ( 'api_domain is required' ) ); 85 | } 86 | 87 | if (empty ($bucketname)) 88 | { 89 | $this->errors->add ( 'empty_bucketname', __ ( 'bucketname is required' ) ); 90 | } 91 | 92 | if (empty ($username)) 93 | { 94 | $this->errors->add ( 'empty_username', __ ( 'username is required' ) ); 95 | } 96 | if (empty ($password)) 97 | { 98 | $this->errors->add ( 'empty_password', __ ( 'password is required' ) ); 99 | } 100 | } 101 | 102 | // -------------------------START form api -------------------------------- // 103 | 104 | private function get_form_api_secret() { 105 | return $this->form_api_secret; 106 | } 107 | 108 | public function check_form_api_internal_error() { 109 | if (!isset($_GET['non-sign'])) { 110 | return false; 111 | } 112 | if( md5("{$_GET['code']}&{$_GET['message']}&{$_GET['url']}&{$_GET['time']}&") == $_GET['non-sign'] ) 113 | { 114 | return true; 115 | } 116 | else 117 | { 118 | return false; 119 | } 120 | } 121 | 122 | public function check_form_api_return_param() { 123 | if (!isset($_GET['sign'])) { 124 | return false; 125 | } 126 | if( md5("{$_GET['code']}&{$_GET['message']}&{$_GET['url']}&{$_GET['time']}&". $this->get_form_api_secret() ) == $_GET['sign'] ) 127 | { 128 | return true; 129 | } 130 | else 131 | { 132 | return false; 133 | } 134 | } 135 | 136 | /** 137 | * md5(policy+'&'+表单API验证密匙) 138 | */ 139 | public function get_form_api_signature($policy) { 140 | return md5($policy . '&' . $this->get_form_api_secret() ); 141 | } 142 | 143 | public function build_policy($args) { 144 | $default = array( 145 | 'expire' => $this->form_api_timeout, // 300 s 146 | 'path' => '/{year}/{mon}/{random}{.suffix}', // full relative path 147 | 'allow_file_ext' => $this->form_api_allowed_ext, 148 | 'content_length_range' =>'0,' . $this->form_api_content_max_length, // 10MB( 10485760) 20MB ( 20971520 ),最大为100MB ( 104857600 ) 149 | 'return_url' => plugins_url('upload.php', HACKLOG_RA_UPYUN_LOADER), 150 | 'notify_url' => '', 151 | ); 152 | $args = array_merge($default,$args); 153 | $policydoc = array( 154 | "bucket" => $args['bucket'], /// 空间名 155 | "expiration" => time() + $args['expire'], /// 该次授权过期时间 156 | "save-key" => $args['path'], /// 命名规则,/2011/12/随机.扩展名 157 | "allow-file-type" => $args['allow_file_ext'], /// 仅允许上传图片 158 | "content-length-range" => $args['content_length_range'] , /// 文件在 100K 以下 159 | "return-url" => $args['return_url'] , /// 回调地址 160 | "notify-url" =>$args['notify_url'] /// 异步回调地址 161 | ); 162 | //var_dump($policydoc); 163 | $policy = base64_encode(json_encode($policydoc)); /// 注意 base64 编码后的 policy字符串中不包含换行符! 164 | return $policy; 165 | } 166 | 167 | /** 168 | * ge_anti_leech_token_sign 169 | *签名格式:MD5(密匙&过期时间&URI){中间8位}+(过期时间) 170 | * 发送cookie或通过get传递 171 | *过期时间格式: UNIX TIME 172 | * @param string $uri 文件路径,必须以/开头 173 | * @return void 174 | */ 175 | public function get_anti_leech_token_sign($uri = '/') { 176 | $uri = '/' . ltrim($uri,'/'); 177 | $end_time = time() + $this->anti_leech_timeout; 178 | $token_sign =md5($this->anti_leech_token . '&' .$end_time.'&' . $uri ); 179 | $sign = substr($token_sign, 12,8).$end_time; 180 | return $sign; 181 | } 182 | 183 | /** 184 | * @param string $uri 185 | * @return string 186 | */ 187 | public function set_anti_leech_token_sign_uri($uri = '/') { 188 | $uri = ltrim($uri,'/'); 189 | return $uri . '?' . self::TOKEN_NAME .'='. $this->get_anti_leech_token_sign($uri); 190 | } 191 | 192 | public function is_url_token_signed($url = '') { 193 | if(strpos($url, self::TOKEN_NAME) > 0 ) 194 | { 195 | return true; 196 | } 197 | else 198 | { 199 | return false; 200 | } 201 | } 202 | 203 | /** 204 | * @param string $uri 205 | * @param string $cookie_path 206 | * @param string $cookie_domain 207 | */ 208 | public function set_anti_leech_token_sign_cookie($uri='/',$cookie_path='/',$cookie_domain='') { 209 | $uri = ltrim($uri,'/'); 210 | setcookie( self::TOKEN_NAME ,$this->get_anti_leech_token_sign($uri),time() + $this->anti_leech_timeout ,$cookie_path,$cookie_domain); 211 | } 212 | // -------------------------END form api -------------------------------- // 213 | 214 | public function safe_sdk_call($func, $args) { 215 | try { 216 | $ret = call_user_func_array([$this, $func], $args); 217 | } catch (UpYunException $e) { 218 | $this->errors->add($e->getCode(), $e->getMessage()); 219 | $ret = false; 220 | if ($this->debug) { 221 | throw $e; 222 | } 223 | } 224 | return $ret; 225 | } 226 | 227 | /** 228 | * @access public 229 | * 230 | * @return bool 231 | */ 232 | public function connect() { 233 | //test for authentication 234 | $finfo = $this->is_file('/'); 235 | if ( !$finfo ) { 236 | return false; //There was an erorr connecting to the server. 237 | } 238 | return true; 239 | } 240 | 241 | /** 242 | * download the file or save to file handler 243 | * @param $file 244 | * @param resource $file_handle 245 | * @return mixed 246 | */ 247 | public function get_contents($file, $file_handle = NULL) { 248 | return $this->safe_sdk_call('readFile', [$file, $file_handle]); 249 | } 250 | 251 | /** 252 | * @param $path target path 253 | * @param $file file content or file handler 254 | * @param bool $auto_mkdir 255 | * @param null $opts 256 | * @return mixed 257 | */ 258 | public function put_contents($path, $file, $auto_mkdir = true, $opts = NULL) { 259 | return $this->safe_sdk_call('writeFile', [$path, $file, $auto_mkdir, $opts]); 260 | } 261 | 262 | /** 263 | * @access public 264 | * 265 | * @param string $source 266 | * @param string $destination 267 | * @param bool $overwrite 268 | * @return bool 269 | */ 270 | public function copy($source, $destination, $overwrite = false) { 271 | $ret = false; 272 | $target_exists = $this->is_file($destination); 273 | if (!$overwrite && $target_exists) { 274 | return true; 275 | } 276 | $tmpf = tmpfile(); 277 | if ($tmpf) { 278 | $this->get_contents($source, $tmpf); 279 | if ($target_exists) { 280 | $this->rm($destination); 281 | } 282 | $ret = $this->put_contents($destination, $tmpf); 283 | @unlink($tmpf); 284 | return $ret; 285 | } 286 | } 287 | 288 | /** 289 | * @access public 290 | * 291 | * @param string $source 292 | * @param string $destination 293 | * @param bool $overwrite 294 | * @return bool 295 | */ 296 | public function move($source, $destination, $overwrite = false) { 297 | if ($this->copy($source, $destination, $overwrite)) { 298 | return $this->rm($source); 299 | } 300 | return false; 301 | } 302 | 303 | /** 304 | * @access public 305 | * 306 | * @param string $file 307 | * @return bool 308 | */ 309 | public function rm($file) { 310 | return $this->safe_sdk_call('delete', [$file]); 311 | } 312 | 313 | /** 314 | * @access public 315 | * 316 | * @param string $file 317 | * @return bool 318 | */ 319 | public function exists($file) { 320 | return $this->safe_sdk_call('getFileInfo', [$file]); 321 | } 322 | 323 | /** 324 | * @access public 325 | * 326 | * @param string $file 327 | * @return bool 328 | */ 329 | public function is_file($file) { 330 | return $this->exists($file); 331 | } 332 | 333 | /** 334 | * @access public 335 | * 336 | * @param string $path 337 | * @return bool 338 | */ 339 | public function is_dir($path) { 340 | return $this->exists($path); 341 | } 342 | 343 | /** 344 | * @access public 345 | * 346 | * @param string $file 347 | * @return bool 348 | */ 349 | public function is_readable($file) { 350 | return $this->exists($file); 351 | } 352 | 353 | /** 354 | * @access public 355 | * 356 | * @param string $file 357 | * @return bool 358 | */ 359 | public function is_writable($file) { 360 | return $this->exists($file); 361 | } 362 | 363 | /** 364 | * @access public 365 | * 366 | * @param string $file 367 | * @return bool 368 | */ 369 | public function atime($file) { 370 | return false; 371 | } 372 | 373 | /** 374 | * @access public 375 | * 376 | * @param string $file 377 | * @return int 378 | */ 379 | public function mtime($file) { 380 | return false; 381 | } 382 | 383 | /** 384 | * @access public 385 | * 386 | * @param string $file 387 | * @return int 388 | */ 389 | public function size($file) { 390 | return false; 391 | } 392 | 393 | /** 394 | * @access public 395 | * 396 | * @param string $file 397 | * @return bool 398 | */ 399 | public function touch($file) { 400 | return false; 401 | } 402 | 403 | /** 404 | * @param $path 405 | * @param bool $auto_mkdir 406 | * @return bool|mixed 407 | */ 408 | public function mkdir($path, $auto_mkdir = true) { 409 | return $this->safe_sdk_call('makeDir', [$path, $auto_mkdir]); 410 | } 411 | 412 | /** 413 | * @access public 414 | * 415 | * @param string $path 416 | * @param bool $recursive 417 | * @return bool 418 | */ 419 | public function rmdir($path, $recursive = false) { 420 | return $this->delete($path, $recursive); 421 | } 422 | 423 | public function get_dir_list($path = '/') { 424 | return $this->safe_sdk_call('getList', [$path]); 425 | } 426 | 427 | public function get_fileinfo($path) { 428 | return $this->safe_sdk_call('getFileInfo', [$path]); 429 | } 430 | 431 | public function get_fold_usage($bucket = '/') { 432 | return $this->safe_sdk_call('getFolderUsage', [$bucket]); 433 | } 434 | 435 | public function get_bucket_usage() { 436 | return $this->safe_sdk_call('getBucketUsage', []); 437 | } 438 | 439 | public function get_api_domain() { 440 | return $this->endpoint; 441 | } 442 | } -------------------------------------------------------------------------------- /images/upyun_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monkey-wenjun/hacklog-remote-attachment-upyun/4c414acd25d6e566afcdf2b4d3976166847c5709/images/upyun_icon.png -------------------------------------------------------------------------------- /includes/bootstrap_compatible.php: -------------------------------------------------------------------------------- 1 | 50 && mt_rand( 0, (int)( $c / 50 ) ) == 1 ) ) { 67 | require_once( ABSPATH . WPINC . '/http.php' ); 68 | $response = wp_remote_get( admin_url( 'upgrade.php?step=1' ), array( 'timeout' => 120, 'httpversion' => '1.1' ) ); 69 | /** This action is documented in wp-admin/network/upgrade.php */ 70 | do_action( 'after_mu_upgrade', $response ); 71 | unset($response); 72 | } 73 | unset($c); 74 | } 75 | } 76 | 77 | require_once(ABSPATH . 'wp-admin/includes/admin.php'); 78 | 79 | auth_redirect(); 80 | 81 | // Schedule trash collection 82 | if ( !wp_next_scheduled('wp_scheduled_delete') && !defined('WP_INSTALLING') ) 83 | wp_schedule_event(time(), 'daily', 'wp_scheduled_delete'); 84 | 85 | set_screen_options(); 86 | 87 | $date_format = get_option('date_format'); 88 | $time_format = get_option('time_format'); 89 | 90 | wp_enqueue_script( 'common' ); 91 | 92 | $editing = false; 93 | 94 | if ( isset($_GET['page']) ) { 95 | $plugin_page = wp_unslash( $_GET['page'] ); 96 | $plugin_page = plugin_basename($plugin_page); 97 | } 98 | 99 | if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) ) 100 | $typenow = $_REQUEST['post_type']; 101 | else 102 | $typenow = ''; 103 | 104 | if ( isset( $_REQUEST['taxonomy'] ) && taxonomy_exists( $_REQUEST['taxonomy'] ) ) 105 | $taxnow = $_REQUEST['taxonomy']; 106 | else 107 | $taxnow = ''; 108 | 109 | if ( WP_NETWORK_ADMIN ) 110 | require(ABSPATH . 'wp-admin/network/menu.php'); 111 | elseif ( WP_USER_ADMIN ) 112 | require(ABSPATH . 'wp-admin/user/menu.php'); 113 | else 114 | require(ABSPATH . 'wp-admin/menu.php'); 115 | 116 | if ( current_user_can( 'manage_options' ) ) { 117 | /** 118 | * Filter the maximum memory limit available for administration screens. 119 | * 120 | * This only applies to administrators, who may require more memory for tasks like updates. 121 | * Memory limits when processing images (uploaded or edited by users of any role) are 122 | * handled separately. 123 | * 124 | * The WP_MAX_MEMORY_LIMIT constant specifically defines the maximum memory limit available 125 | * when in the administration back-end. The default is 256M, or 256 megabytes of memory. 126 | * 127 | * @since 3.0.0 128 | * 129 | * @param string 'WP_MAX_MEMORY_LIMIT' The maximum WordPress memory limit. Default 256M. 130 | */ 131 | @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) ); 132 | } 133 | 134 | /** 135 | * Fires as an admin screen or script is being initialized. 136 | * 137 | * Note, this does not just run on user-facing admin screens. 138 | * It runs on admin-ajax.php and admin-post.php as well. 139 | * 140 | * This is roughly analgous to the more general 'init' hook, which fires earlier. 141 | * 142 | * @since 2.5.0 143 | */ 144 | do_action( 'admin_init' ); 145 | 146 | if ( isset($plugin_page) ) { 147 | if ( !empty($typenow) ) 148 | $the_parent = $pagenow . '?post_type=' . $typenow; 149 | else 150 | $the_parent = $pagenow; 151 | if ( ! $page_hook = get_plugin_page_hook($plugin_page, $the_parent) ) { 152 | $page_hook = get_plugin_page_hook($plugin_page, $plugin_page); 153 | // backwards compatibility for plugins using add_management_page 154 | if ( empty( $page_hook ) && 'edit.php' == $pagenow && '' != get_plugin_page_hook($plugin_page, 'tools.php') ) { 155 | // There could be plugin specific params on the URL, so we need the whole query string 156 | if ( !empty($_SERVER[ 'QUERY_STRING' ]) ) 157 | $query_string = $_SERVER[ 'QUERY_STRING' ]; 158 | else 159 | $query_string = 'page=' . $plugin_page; 160 | wp_redirect( admin_url('tools.php?' . $query_string) ); 161 | exit; 162 | } 163 | } 164 | unset($the_parent); 165 | } 166 | 167 | $hook_suffix = ''; 168 | if ( isset($page_hook) ) 169 | $hook_suffix = $page_hook; 170 | else if ( isset($plugin_page) ) 171 | $hook_suffix = $plugin_page; 172 | else if ( isset($pagenow) ) 173 | $hook_suffix = $pagenow; 174 | 175 | set_current_screen(); 176 | 177 | // Handle plugin admin pages. 178 | if ( isset($plugin_page) ) { 179 | if ( $page_hook ) { 180 | /** 181 | * Fires before a particular screen is loaded. 182 | * 183 | * The load-* hook fires in a number of contexts. This hook is for plugin screens 184 | * where a callback is provided when the screen is registered. 185 | * 186 | * The dynamic portion of the hook name, $page_hook, refers to a mixture of plugin 187 | * page information including: 188 | * 1. The page type. If the plugin page is registered as a submenu page, such as for 189 | * Settings, the page type would be 'settings'. Otherwise the type is 'toplevel'. 190 | * 2. A separator of '_page_'. 191 | * 3. The plugin basename minus the file extension. 192 | * 193 | * Together, the three parts form the $page_hook. Citing the example above, 194 | * the hook name used would be 'load-settings_page_pluginbasename'. 195 | * 196 | * @see get_plugin_page_hook() 197 | * 198 | * @since 2.1.0 199 | */ 200 | do_action( 'load-' . $page_hook ); 201 | if (! isset($_GET['noheader'])) 202 | require_once(ABSPATH . 'wp-admin/admin-header.php'); 203 | 204 | /** 205 | * Used to call the registered callback for a plugin screen. 206 | * 207 | * @access private 208 | * 209 | * @since 1.5.0 210 | */ 211 | do_action( $page_hook ); 212 | } else { 213 | if ( validate_file($plugin_page) ) 214 | wp_die(__('Invalid plugin page')); 215 | 216 | if ( !( file_exists(WP_PLUGIN_DIR . "/$plugin_page") && is_file(WP_PLUGIN_DIR . "/$plugin_page") ) && !( file_exists(WPMU_PLUGIN_DIR . "/$plugin_page") && is_file(WPMU_PLUGIN_DIR . "/$plugin_page") ) ) 217 | wp_die(sprintf(__('Cannot load %s.'), htmlentities($plugin_page))); 218 | 219 | /** 220 | * Fires before a particular screen is loaded. 221 | * 222 | * The load-* hook fires in a number of contexts. This hook is for plugin screens 223 | * where the file to load is directly included, rather than the use of a function. 224 | * 225 | * The dynamic portion of the hook name, $plugin_page, refers to the plugin basename. 226 | * 227 | * @see plugin_basename() 228 | * 229 | * @since 1.5.0 230 | */ 231 | do_action( 'load-' . $plugin_page ); 232 | 233 | if ( !isset($_GET['noheader'])) 234 | require_once(ABSPATH . 'wp-admin/admin-header.php'); 235 | 236 | if ( file_exists(WPMU_PLUGIN_DIR . "/$plugin_page") ) 237 | include(WPMU_PLUGIN_DIR . "/$plugin_page"); 238 | else 239 | include(WP_PLUGIN_DIR . "/$plugin_page"); 240 | } 241 | 242 | include(ABSPATH . 'wp-admin/admin-footer.php'); 243 | 244 | exit(); 245 | } else if (isset($_GET['import'])) { 246 | 247 | $importer = $_GET['import']; 248 | 249 | if ( ! current_user_can('import') ) 250 | wp_die(__('You are not allowed to import.')); 251 | 252 | if ( validate_file($importer) ) { 253 | wp_redirect( admin_url( 'import.php?invalid=' . $importer ) ); 254 | exit; 255 | } 256 | 257 | if ( ! isset($wp_importers[$importer]) || ! is_callable($wp_importers[$importer][2]) ) { 258 | wp_redirect( admin_url( 'import.php?invalid=' . $importer ) ); 259 | exit; 260 | } 261 | 262 | /** 263 | * Fires before an importer screen is loaded. 264 | * 265 | * The dynamic portion of the hook name, $importer, refers to the importer slug. 266 | * 267 | * @since 3.5.0 268 | */ 269 | do_action( 'load-importer-' . $importer ); 270 | 271 | $parent_file = 'tools.php'; 272 | $submenu_file = 'import.php'; 273 | $title = __('Import'); 274 | 275 | if (! isset($_GET['noheader'])) 276 | require_once(ABSPATH . 'wp-admin/admin-header.php'); 277 | 278 | require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); 279 | 280 | define('WP_IMPORTING', true); 281 | 282 | /** 283 | * Whether to filter imported data through kses on import. 284 | * 285 | * Multisite uses this hook to filter all data through kses by default, 286 | * as a super administrator may be assisting an untrusted user. 287 | * 288 | * @since 3.1.0 289 | * 290 | * @param bool false Whether to force data to be filtered through kses. Default false. 291 | */ 292 | if ( apply_filters( 'force_filtered_html_on_import', false ) ) 293 | kses_init_filters(); // Always filter imported data with kses on multisite. 294 | 295 | call_user_func($wp_importers[$importer][2]); 296 | 297 | include(ABSPATH . 'wp-admin/admin-footer.php'); 298 | 299 | // Make sure rules are flushed 300 | flush_rewrite_rules(false); 301 | 302 | exit(); 303 | } else { 304 | /** 305 | * Fires before a particular screen is loaded. 306 | * 307 | * The load-* hook fires in a number of contexts. This hook is for core screens. 308 | * 309 | * The dynamic portion of the hook name, $pagenow, is a global variable 310 | * referring to the filename of the current page, such as 'admin.php', 311 | * 'post-new.php' etc. A complete hook for the latter would be 'load-post-new.php'. 312 | * 313 | * @since 2.1.0 314 | */ 315 | do_action( 'load-' . $pagenow ); 316 | // Backwards compatibility with old load-page-new.php, load-page.php, 317 | // and load-categories.php actions. 318 | if ( $typenow == 'page' ) { 319 | if ( $pagenow == 'post-new.php' ) 320 | do_action( 'load-page-new.php' ); 321 | elseif ( $pagenow == 'post.php' ) 322 | do_action( 'load-page.php' ); 323 | } elseif ( $pagenow == 'edit-tags.php' ) { 324 | if ( $taxnow == 'category' ) 325 | do_action( 'load-categories.php' ); 326 | elseif ( $taxnow == 'link_category' ) 327 | do_action( 'load-edit-link-categories.php' ); 328 | } 329 | } 330 | 331 | if ( ! empty( $_REQUEST['action'] ) ) { 332 | /** 333 | * Fires when an 'action' request variable is sent. 334 | * 335 | * The dynamic portion of the hook name, $_REQUEST['action'], 336 | * refers to the action derived from the GET or POST request. 337 | * 338 | * @since 2.6.0 339 | */ 340 | do_action( 'admin_action_' . $_REQUEST['action'] ); 341 | } 342 | -------------------------------------------------------------------------------- /includes/hacklogra_upyun.class.php: -------------------------------------------------------------------------------- 1 | 6 | * @link http://ihacklog.com 7 | * @copyright Copyright (C) 2012 荒野无灯 8 | * @license http://www.gnu.org/licenses/ 9 | */ 10 | if (!defined('ABSPATH')) { 11 | die('What are you doing?'); 12 | } 13 | 14 | require __DIR__ . '/../filesystem/upyun.php'; 15 | 16 | class hacklogra_upyun 17 | { 18 | const textdomain = 'hacklog-remote-attachment'; 19 | const plugin_name = 'Hacklog Remote Attachment Upyun'; 20 | //the same 21 | const opt_space = 'hacklogra_remote_filesize'; 22 | //new option name 23 | const opt_primary = 'hacklogra_upyun_options'; 24 | const version = '1.4.4-upyun-ported-from-1.2.6-origin'; 25 | private static $img_ext = array('jpg', 'jpeg', 'png', 'gif', 'bmp'); 26 | private static $rest_user = 'admin'; 27 | private static $rest_pwd = '4d4173594c77453d'; 28 | private static $rest_server = 'v0.api.upyun.com'; 29 | private static $bucketname = ''; 30 | private static $form_api_secret = ''; 31 | private static $form_api_content_max_length = 100; 32 | private static $form_api_allowed_ext = 'jpg,jpeg,gif,png,doc,pdf,zip,rar,tar.gz,tar.bz2,7z'; 33 | private static $form_api_timeout = 300; 34 | private static $anti_leech_token = ''; 35 | private static $anti_leech_timeout = 600; 36 | private static $rest_port = 80; 37 | private static $rest_timeout = 30; 38 | private static $subdir = ''; 39 | private static $rest_remote_path = 'wp-files'; 40 | private static $http_remote_path = 'wp-files'; 41 | private static $remote_url = ''; 42 | private static $remote_baseurl = ''; 43 | private static $local_basepath = ''; 44 | private static $local_path = ''; 45 | private static $local_url = ''; 46 | private static $local_baseurl = ''; 47 | /** 48 | * @var Filesystem_Upyun 49 | */ 50 | private static $fs = null; 51 | private static $is_form_api_upload = false; 52 | 53 | public function __construct() 54 | { 55 | self::init(); 56 | //this should always check 57 | add_action('admin_notices', array(__CLASS__, 'check_rest_connection')); 58 | //should load before 'admin_menu' hook ... so,use init hook 59 | add_action('init', array(__CLASS__, 'load_textdomain')); 60 | //menu 61 | add_action('admin_menu', array(__CLASS__, 'plugin_menu')); 62 | //HOOK the upload, use init to support xmlrpc upload 63 | add_action('init', array(__CLASS__, 'admin_init')); 64 | //frontend filter,filter on image only 65 | add_filter('wp_get_attachment_url', array(__CLASS__, 'replace_baseurl'), -999); 66 | add_action('wp_ajax_hacklogra_upyun_signature', array(__CLASS__, 'return_signature')); 67 | add_action('media_buttons', array(__CLASS__, 'add_media_button'), 11); 68 | add_action('plugin_action_links_' . plugin_basename(HACKLOG_RA_UPYUN_LOADER), array(__CLASS__, 'add_plugin_actions')); 69 | empty(self::$anti_leech_token) || add_filter('the_content', array(__CLASS__, 'sign_post_url')); 70 | self::setup_rest(); 71 | // self::$fs->debug = true; 72 | } 73 | 74 | ############################## PRIVATE FUNCTIONS ############################################## 75 | 76 | private static function update_options() 77 | { 78 | $value = self::get_default_opts(); 79 | $keys = array_keys($value); 80 | foreach ($keys as $key) { 81 | if (!empty($_POST[$key])) { 82 | $value[$key] = addslashes(trim($_POST[$key])); 83 | } 84 | } 85 | $value['remote_baseurl'] = rtrim($value['remote_baseurl'], '/'); 86 | $value['rest_remote_path'] = rtrim($value['rest_remote_path'], '/'); 87 | $value['http_remote_path'] = rtrim($value['http_remote_path'], '/'); 88 | if (update_option(self::opt_primary, $value)) 89 | return TRUE; 90 | else 91 | return FALSE; 92 | } 93 | 94 | /** 95 | * get file extension 96 | * @static 97 | * @param $path 98 | * @return mixed 99 | */ 100 | private static function get_ext($path) 101 | { 102 | return pathinfo($path, PATHINFO_EXTENSION); 103 | } 104 | 105 | /** 106 | * to see if a file is an image file. 107 | * @static 108 | * @param $path 109 | * @return bool 110 | */ 111 | private static function is_image_file($path) 112 | { 113 | return in_array(self::get_ext($path), self::$img_ext); 114 | } 115 | 116 | /** 117 | * get the default options 118 | * @static 119 | * @return array 120 | */ 121 | private static function get_default_opts() 122 | { 123 | return array( 124 | 'rest_user' => self::$rest_user, 125 | 'rest_pwd' => self::$rest_pwd, 126 | 'form_api_secret' => self::$form_api_secret, 127 | 'form_api_content_max_length' => self::$form_api_content_max_length, 128 | 'form_api_allowed_ext' => self::$form_api_allowed_ext, 129 | 'form_api_timeout' => self::$form_api_timeout, 130 | 'anti_leech_token' => self::$anti_leech_token, 131 | 'anti_leech_timeout' => self::$anti_leech_timeout, 132 | 'rest_server' => self::$rest_server, 133 | 'bucketname' => self::$bucketname, 134 | 'rest_port' => self::$rest_port, 135 | 'rest_timeout' => self::$rest_timeout, 136 | 'rest_remote_path' => self::$rest_remote_path, 137 | 'http_remote_path' => self::$http_remote_path, 138 | 'remote_baseurl' => self::$remote_baseurl, 139 | ); 140 | } 141 | 142 | /** 143 | * increase the filesize,keep the filesize tracked. 144 | * @static 145 | * @param $file 146 | * @return void 147 | */ 148 | private static function update_filesize_used($file) 149 | { 150 | if (file_exists($file)) { 151 | $filesize = filesize($file); 152 | $previous_value = get_option(self::opt_space); 153 | $to_save = $previous_value + $filesize; 154 | update_option(self::opt_space, $to_save); 155 | } 156 | } 157 | 158 | /** 159 | * decrease the filesize when a remote file is deleted. 160 | * @static 161 | * @param $fs 162 | * @param $file 163 | * @return void 164 | */ 165 | private static function decrease_filesize_used($fs, $file) 166 | { 167 | if ($fs->exists($file)) { 168 | $filesize = $fs->size($file); 169 | $previous_value = get_option(self::opt_space); 170 | $to_save = $previous_value - $filesize; 171 | update_option(self::opt_space, $to_save); 172 | } 173 | } 174 | 175 | /** 176 | * like wp_handle_upload_error in file.php under wp-admin/includes 177 | * @param $message 178 | * @return array 179 | */ 180 | public static function handle_upload_error($message) 181 | { 182 | return array('error' => $message); 183 | } 184 | 185 | public static function xmlrpc_error($errorString = '') 186 | { 187 | return new IXR_Error(500, $errorString); 188 | } 189 | 190 | /** 191 | * report upload error 192 | * @return type 193 | */ 194 | private static function raise_upload_error() 195 | { 196 | $error_str = sprintf('%s:' . __('upload file to remote server failed!', self::textdomain), self::plugin_name); 197 | if (defined('XMLRPC_REQUEST')) { 198 | return self::xmlrpc_error($error_str); 199 | } else { 200 | return call_user_func(array(__CLASS__, 'handle_upload_error'), $error_str); 201 | } 202 | } 203 | 204 | /** 205 | * report rest connection error 206 | * @return type 207 | */ 208 | private static function raise_connection_error() 209 | { 210 | $error_message = 'Unknown Error!'; 211 | $all_errors = self::$fs->errors->get_error_messages(); 212 | if (count($all_errors) > 0) { 213 | $error_message = implode('|', $all_errors); 214 | } 215 | $error_message = '' . $error_message . ''; 216 | $error_str = sprintf('%s:' . $error_message, self::plugin_name); 217 | if (defined('XMLRPC_REQUEST')) { 218 | return self::xmlrpc_error($error_str); 219 | } else { 220 | return call_user_func(array(__CLASS__, 'handle_upload_error'), $error_str); 221 | } 222 | } 223 | 224 | ############################## PUBLIC FUNCTIONS ############################################## 225 | /** 226 | * init 227 | * @static 228 | * @return void 229 | */ 230 | 231 | public static function init() 232 | { 233 | register_activation_hook(HACKLOG_RA_UPYUN_LOADER, array(__CLASS__, 'my_activation')); 234 | register_deactivation_hook(HACKLOG_RA_UPYUN_LOADER, array(__CLASS__, 'my_deactivation')); 235 | $opts = get_option(self::opt_primary); 236 | self::$rest_user = $opts['rest_user']; 237 | self::$rest_pwd = $opts['rest_pwd']; 238 | self::$form_api_secret = $opts['form_api_secret']; 239 | self::$form_api_allowed_ext = $opts['form_api_allowed_ext']; 240 | self::$form_api_content_max_length = $opts['form_api_content_max_length']; 241 | self::$form_api_timeout = $opts['form_api_timeout']; 242 | self::$anti_leech_token = $opts['anti_leech_token']; 243 | self::$anti_leech_timeout = $opts['anti_leech_timeout']; 244 | self::$rest_server = $opts['rest_server']; 245 | self::$bucketname = $opts['bucketname']; 246 | self::$rest_port = $opts['rest_port']; 247 | self::$rest_timeout = $opts['rest_timeout'] > 0 ? $opts['rest_timeout'] : 30; 248 | 249 | $opts['rest_remote_path'] = rtrim($opts['rest_remote_path'], '/'); 250 | $opts['http_remote_path'] = rtrim($opts['http_remote_path'], '/'); 251 | $opts['remote_baseurl'] = rtrim($opts['remote_baseurl'], '/'); 252 | $upload_dir = wp_upload_dir(); 253 | //be aware of / in the end 254 | self::$local_basepath = $upload_dir['basedir']; 255 | self::$local_path = $upload_dir['path']; 256 | self::$local_baseurl = $upload_dir['baseurl']; 257 | self::$local_url = $upload_dir['url']; 258 | self::$subdir = $upload_dir['subdir']; 259 | //if the post publish date was different from the media upload date,the time should take from the database. 260 | if (get_option('uploads_use_yearmonth_folders') && isset($_REQUEST['post_id'])) { 261 | $post_id = (int)$_REQUEST['post_id']; 262 | if ($post = get_post($post_id)) { 263 | if (substr($post->post_date, 0, 4) > 0) { 264 | $time = $post->post_date; 265 | $y = substr($time, 0, 4); 266 | $m = substr($time, 5, 2); 267 | $subdir = "/$y/$m"; 268 | self::$subdir = $subdir; 269 | } 270 | } 271 | } 272 | //后面不带 / 273 | self::$rest_remote_path = $opts['rest_remote_path'] == '.' ? '' : $opts['rest_remote_path']; 274 | self::$http_remote_path = $opts['http_remote_path'] == '.' ? '' : $opts['http_remote_path']; 275 | //此baseurl与options里面的不同! 276 | self::$remote_baseurl = '.' == self::$http_remote_path ? $opts['remote_baseurl'] : 277 | $opts['remote_baseurl'] . '/' . self::$http_remote_path; 278 | self::$remote_url = self::$remote_baseurl . self::$subdir; 279 | } 280 | 281 | public static function handle_form_api_upload($post_id, $post_data = array()) 282 | { 283 | if (!self::setup_rest()) { 284 | return new WP_Error('hacklogra_internal_error', 'failed to contruct Upyun class'); 285 | } 286 | self::$is_form_api_upload = true; 287 | //check_admin_referer('media-form'); 288 | // Upload File button was clicked 289 | if (self::$fs->check_form_api_internal_error()) { 290 | $id = new WP_Error('upyun_internal_error', __('Upyun internal Error!')); 291 | } else 292 | if ($_GET['code'] == '200') { 293 | if (self::$fs->check_form_api_return_param()) { 294 | $url = self::$remote_baseurl . ltrim($_GET['url'], '/'); 295 | //error_log(var_export(array(self::$remote_baseurl ,$_GET['url']),true)); 296 | $filename = basename($_GET['url']); 297 | $ft = wp_check_filetype($filename, null); 298 | $type = $ft['type']; 299 | $file = str_replace('/' . self::$http_remote_path . '/', '', $_GET['url']); 300 | $name_parts = pathinfo($filename); 301 | $name = trim(substr($filename, 0, -(1 + strlen($name_parts['extension'])))); 302 | $title = $name; 303 | $content = ''; 304 | // Construct the attachment array 305 | $attachment = array_merge(array( 306 | 'post_mime_type' => $type, 307 | 'guid' => $url, 308 | 'post_parent' => $post_id, 309 | 'post_title' => $title, 310 | 'post_content' => $content, 311 | ), $post_data); 312 | 313 | // This should never be set as it would then overwrite an existing attachment. 314 | if (isset($attachment['ID'])) 315 | unset($attachment['ID']); 316 | 317 | // Save the data 318 | $id = wp_insert_attachment($attachment, $file, $post_id); 319 | if (!is_wp_error($id)) { 320 | wp_update_attachment_metadata($id, wp_generate_attachment_metadata($id, $file)); 321 | } 322 | 323 | } 324 | } else { 325 | $id = new WP_Error('upyun_upload_error', $_GET['message']); 326 | } 327 | return $id; 328 | } 329 | 330 | 331 | public static function return_signature() 332 | { 333 | if (!self::setup_rest()) { 334 | die(json_encode(array('error' => 'yes', 'message' => 'failed to contruct Upyun class'))); 335 | } 336 | $post_id = $_POST['post_id']; 337 | $filename = basename($_POST['file']); 338 | $unique_filename = self::unique_filename(self::$rest_remote_path . self::$subdir, $filename); 339 | $policy = self::$fs->build_policy( 340 | array('path' => '/' . self::$rest_remote_path . self::$subdir . '/' . $unique_filename, 341 | 'return_url' => plugins_url('upload.php?post_id=' . $post_id, HACKLOG_RA_UPYUN_LOADER), 342 | 'bucket' => self::$bucketname, 343 | )); 344 | $signature = self::$fs->get_form_api_signature($policy); 345 | header("Content-Type: text/json;Charset=UTF-8"); 346 | die(json_encode(array('policy' => $policy, 'signature' => $signature, 'error' => 'none'))); 347 | } 348 | 349 | public static function add_media_button($editor_id = 'content') 350 | { 351 | global $post_ID; 352 | $url = plugins_url("upload.php?post_id={$post_ID}&TB_iframe=1&width=640&height=451&tab=upyun", HACKLOG_RA_UPYUN_LOADER); 353 | $admin_icon = plugins_url('images/upyun_icon.png', HACKLOG_RA_UPYUN_LOADER); 354 | if (is_ssl()) { 355 | $url = str_replace('http://', 'https://', $url); 356 | } 357 | $alt = __('Upload local file to Upyun server', self::textdomain); 358 | $img = '' . esc_attr($alt) . ''; 359 | 360 | echo '' . $img . ''; 361 | } 362 | 363 | public static function media_upload_type_form_upyun($type = 'file', $errors = null, $id = null) 364 | { 365 | 366 | $post_id = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : 0; 367 | if (!self::connect_remote_server()) { 368 | return self::raise_connection_error(); 369 | } 370 | 371 | media_upload_header(); 372 | 373 | $upyun_form_action_url = 'http://' . self::$fs->get_api_domain() . '/' . self::$bucketname . '/'; 374 | if (isset($_GET['code']) && isset($_GET['message']) && isset($_GET['url']) && isset($_GET['time']) && isset($_GET['sign'])) { 375 | $form_action_url = plugins_url('upload.php?post_id=' . $post_id . '&TB_iframe=1&width=640&height=451', HACKLOG_RA_UPYUN_LOADER); 376 | } else { 377 | $form_action_url = $upyun_form_action_url; 378 | } 379 | 380 | $form_class = 'media-upload-form type-form validate'; 381 | 382 | //if ( get_user_setting('uploader') ) 383 | $form_class .= ' html-uploader'; 384 | ?> 385 | 386 |
388 | 389 | 390 | 391 | 392 | 393 | 394 |

395 |

396 | 397 |
398 | 399 |

400 | 401 | 402 | 415 | 416 |
417 | ' . esc_html($id->get_error_message()) . '
'; 424 | exit; 425 | } 426 | } 427 | ?> 428 | 429 |

430 | 431 |

432 |
433 | 505 | set_anti_leech_token_sign_uri($file_path); 545 | return $signed_url; 546 | } 547 | 548 | 549 | public static function sign_post_url($content) 550 | { 551 | if (!empty(self::$anti_leech_token) && preg_match_all("@" . self::$remote_baseurl . "[^'\"\[]+@i", $content, $matches)) { 552 | if (isset($matches[0]) && count($matches[0]) > 0) { 553 | $urls = $matches[0]; 554 | //strip the duplicaated urls 555 | $urls = array_unique($urls); 556 | self::setup_rest(); 557 | foreach ($urls as $url) { 558 | //the determine should be here ,not sign_url function 559 | if (self::$fs->is_url_token_signed($url)) { 560 | continue; 561 | } 562 | $signed_url = self::sign_url($url); 563 | $content = str_replace($url, $signed_url, $content); 564 | } 565 | } 566 | } 567 | //var_dump($content); 568 | return $content; 569 | } 570 | 571 | public static function sign_attachment_url($url) 572 | { 573 | if (strcasecmp(substr($url, 0, strlen(self::$remote_baseurl)), self::$remote_baseurl) == 0) { 574 | self::setup_rest(); 575 | $url = self::sign_url($url); 576 | } 577 | return $url; 578 | } 579 | 580 | /** 581 | * humanize file size. 582 | * @static 583 | * @param $bytes 584 | * @return string 585 | */ 586 | public static function human_size($bytes) 587 | { 588 | $types = array('B', 'KB', 'MB', 'GB', 'TB'); 589 | for ($i = 0; $bytes >= 1024 && $i < (count($types) - 1); $bytes /= 1024, $i++) 590 | ; 591 | return (round($bytes, 2) . " " . $types[$i]); 592 | } 593 | 594 | /** 595 | * load the textdomain on init 596 | * @static 597 | * @return void 598 | */ 599 | public static function load_textdomain() 600 | { 601 | load_plugin_textdomain(self::textdomain, false, basename(dirname(HACKLOG_RA_UPYUN_LOADER)) . '/languages/'); 602 | } 603 | 604 | /** 605 | * @since 1.2.1 606 | * note that admin_menu runs before admin_init 607 | */ 608 | public static function admin_init() 609 | { 610 | //DO NOT HOOK the update or upgrade page for that they may upload zip file. 611 | $current_page = basename($_SERVER['SCRIPT_FILENAME']); 612 | switch ($current_page) { 613 | // wp-admin/update.php?action=upload-plugin 614 | // wp-admin/update.php?action=upload-theme 615 | case 'update.php': 616 | //update-core.php?action=do-core-reinstall 617 | case 'update-core.php': 618 | //JUST DO NOTHING ,SKIP. 619 | break; 620 | default: 621 | add_filter('wp_handle_upload', array(__CLASS__, 'upload_and_send')); 622 | add_filter('media_send_to_editor', array(__CLASS__, 'replace_attachurl'), -999); 623 | add_filter('wp_calculate_image_srcset', array(__CLASS__, 'replace_attachurl_srcset'), -999, 5); 624 | add_filter('attachment_link', array(__CLASS__, 'replace_baseurl'), -999); 625 | //生成缩略图后立即上传生成的文件并删除本地文件,this must after watermark generate 626 | add_filter('wp_update_attachment_metadata', array(__CLASS__, 'upload_images'), 999); 627 | //删除远程附件 628 | add_action('wp_delete_file', array(__CLASS__, 'delete_remote_file')); 629 | break; 630 | } 631 | } 632 | 633 | /** 634 | * set up rest connection 635 | * @static 636 | * @param $args 637 | * @return bool 638 | */ 639 | public static function setup_rest($args = null) 640 | { 641 | //if object not inited. 642 | if (null == self::$fs) { 643 | $credentials = [ 644 | 'api_domain' => self::$rest_server, 645 | 'timeout' => self::$rest_timeout, 646 | 'bucketname' => self::$bucketname, 647 | 'username' => self::$rest_user, 648 | 'password' => self::$rest_pwd, 649 | ]; 650 | $form_api_params = [ 651 | 'form_api_secret' => self::$form_api_secret, 652 | 'form_api_allowed_ext' => self::$form_api_allowed_ext, 653 | 'form_api_content_max_length' => self::$form_api_content_max_length, 654 | 'form_api_timeout' => self::$form_api_timeout, 655 | 'anti_leech_token' => self::$anti_leech_token, 656 | 'anti_leech_timeout' => self::$anti_leech_timeout, 657 | ]; 658 | if (null != $args) { 659 | $credentials = array_merge($credentials, $args); 660 | } 661 | self::$fs = new Filesystem_Upyun($credentials['bucketname'], $credentials['username'], $credentials['password'], $credentials['api_domain'], $credentials['timeout']); 662 | if (!self::$fs) { 663 | return false; 664 | } 665 | self::$fs->set_form_api_params($form_api_params); 666 | } 667 | return true; 668 | } 669 | 670 | /** 671 | * do connecting to server.DO NOT call this on any page that not needed! 672 | * if can not connect to remote server successfully,the plugin will refuse to work 673 | * @static 674 | * @return void 675 | */ 676 | public static function connect_remote_server($args = null) 677 | { 678 | self::setup_rest(); 679 | //just call the setup and test the authentication 680 | return self::$fs->connect(); 681 | } 682 | 683 | /** 684 | * notice the user to setup the plugin options 685 | * MUST run after self::init(); 686 | */ 687 | public static function check_rest_connection() 688 | { 689 | $current_page = basename($_SERVER['SCRIPT_FILENAME']); 690 | if ('plugins.php' == $current_page) { 691 | if (!self::connect_remote_server()) { 692 | $error = self::raise_connection_error(); 693 | $redirect_msg = sprintf(__('Click here to setup the plugin options.', self::textdomain), admin_url('options-general.php?page=' . md5(HACKLOG_RA_UPYUN_LOADER))); 694 | echo '

' . $error['error'] . '
' . $redirect_msg . '

'; 695 | } 696 | } 697 | } 698 | 699 | /** 700 | * the hook is in function get_attachment_link() 701 | * @static 702 | * @param $html 703 | * @return mixed 704 | */ 705 | public static function replace_attachurl($html) 706 | { 707 | $html = str_replace(self::$local_url, self::$remote_url, $html); 708 | return $html; 709 | } 710 | 711 | /** 712 | * @param $sources 713 | * @param $size_array 714 | * @param $image_src 715 | * @param $image_meta 716 | * @param $attachment_id 717 | * @return mixed 718 | */ 719 | public static function replace_attachurl_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) 720 | { 721 | $local_url = self::$local_url; 722 | // using the same logic as WP 723 | global $wp_version; 724 | 725 | if (version_compare($wp_version, "4.5", '>=') && is_ssl() && 'https' !== substr($local_url, 0, 5) && parse_url($local_url, PHP_URL_HOST) === $_SERVER['HTTP_HOST']) { 726 | $local_url = set_url_scheme($local_url, 'https'); 727 | } 728 | foreach ((array)$sources as $index => $source) { 729 | $sources[$index]['url'] = str_replace($local_url, self::$remote_url, $source['url']); 730 | } 731 | return $sources; 732 | } 733 | 734 | /** 735 | * the hook is in function media_send_to_editor 736 | * @static 737 | * @param $html 738 | * @return mixed 739 | */ 740 | public static function replace_baseurl($url) 741 | { 742 | $url = str_replace(self::$local_baseurl, self::$remote_baseurl, $url); 743 | !empty(self::$anti_leech_token) && !is_admin() && self::setup_rest() && $url = self::sign_url($url); 744 | return $url; 745 | } 746 | 747 | /** 748 | * handle orig image file and other files. 749 | * @static 750 | * @param $file 751 | * @return array|mixed 752 | */ 753 | public static function upload_and_send($file) 754 | { 755 | if (self::$is_form_api_upload) { 756 | return $file; 757 | } 758 | /** 759 | * 泥马, xmlrpc mw_newMediaObject 方法中的 wp_handle_upload HOOK file 参数仅为文件名! 760 | */ 761 | if (defined('XMLRPC_REQUEST')) { 762 | $file['file'] = self::$local_path . '/' . $file['file']; 763 | } 764 | if (!self::connect_remote_server()) { 765 | //failed ,delete the orig file 766 | file_exists($file['file']) && unlink($file['file']); 767 | return self::raise_connection_error(); 768 | } 769 | $upload_error_handler = 'wp_handle_upload_error'; 770 | 771 | $local_basename = basename($file['file']); 772 | $local_basename_unique = self::unique_filename(self::$rest_remote_path . self::$subdir, $local_basename); 773 | /** 774 | * since we can not detect wether remote file is duplicated or not. 775 | * if remote already has the file,then first rename local filename to target.after this,the file uploaded to remote 776 | * server should not overwrote the existed file. 777 | */ 778 | if ($local_basename_unique != $local_basename) { 779 | $local_full_filename = dirname($file['file']) . '/' . $local_basename_unique; 780 | @rename($file['file'], $local_full_filename); 781 | $file['file'] = $local_full_filename; 782 | } 783 | $localfile = $file['file']; 784 | //file path on remote server 785 | $remotefile = self::$rest_remote_path . self::$subdir . '/' . $local_basename_unique; 786 | $remote_subdir = dirname($remotefile); 787 | $remote_subdir = str_replace('\\', '/', $remote_subdir); 788 | 789 | $file['url'] = str_replace(self::$local_url, self::$remote_url, $file['url']); 790 | //如果是图片,此处不处理,因为要与水印插件兼容的原因  791 | if (self::is_image_file($file['file'])) { 792 | //对xmlrpc 这里又给它还原 793 | if (defined('XMLRPC_REQUEST')) { 794 | $file['file'] = basename($file['file']); 795 | } 796 | return $file; 797 | } 798 | $content = file_get_contents($localfile); 799 | // return array('error'=> $remotefile); 800 | if (!self::$fs->put_contents($remotefile, $content, true)) { 801 | $error_str = sprintf('%s:' . __('upload file to remote server failed!', self::textdomain), self::plugin_name); 802 | if (defined('XMLRPC_REQUEST')) { 803 | return self::xmlrpc_error($error_str); 804 | } else { 805 | return call_user_func($upload_error_handler, $file, $error_str); 806 | } 807 | } 808 | unset($content); 809 | //uploaded successfully 810 | self::update_filesize_used($localfile); 811 | //delete the local file 812 | file_exists($file['file']) && unlink($file['file']); 813 | //对于非图片文件,且为xmlrpc的情况,还原file参数 814 | if (defined('XMLRPC_REQUEST')) { 815 | $file['file'] = basename($file['file']); 816 | } 817 | return $file; 818 | } 819 | 820 | /** 821 | * 上传缩略图到远程服务器并删除本地服务器文件 822 | * @static 823 | * @param $metadata from function wp_generate_attachment_metadata 824 | * @return array 825 | */ 826 | public static function upload_images($metadata) 827 | { 828 | if (self::$is_form_api_upload) { 829 | return $metadata; 830 | } 831 | if (!self::is_image_file($metadata['file'])) { 832 | return $metadata; 833 | } 834 | 835 | if (!self::connect_remote_server()) { 836 | return self::raise_connection_error(); 837 | } 838 | 839 | //deal with fullsize image file 840 | if (!self::upload_file($metadata['file'])) { 841 | return self::raise_upload_error(); 842 | } 843 | 844 | 845 | if (isset($metadata['sizes']) && count($metadata['sizes']) > 0) { 846 | //there may be duplicated filenames,so .... 847 | $unique_images = array(); 848 | foreach ($metadata['sizes'] as $image_size => $image_item) { 849 | $unique_images[] = $image_item['file']; 850 | } 851 | $unique_images = array_unique($unique_images); 852 | foreach ($unique_images as $image_filename) { 853 | $relative_filepath = dirname($metadata['file']) . '/' . $image_filename; 854 | if (!self::upload_file($relative_filepath)) { 855 | return self::raise_upload_error(); 856 | } 857 | } 858 | } 859 | return $metadata; 860 | } 861 | 862 | /** 863 | * upload single file to remote rest server, used by upload_images 864 | * @param type $relative_path the path relative to upload basedir 865 | * @return type 866 | */ 867 | private static function upload_file($relative_path) 868 | { 869 | $local_filepath = self::$local_basepath . DIRECTORY_SEPARATOR . $relative_path; 870 | $local_basename = basename($local_filepath); 871 | $remotefile = self::$rest_remote_path . self::$subdir . '/' . $local_basename; 872 | $file_data = file_get_contents($local_filepath); 873 | if (!self::$fs->put_contents($remotefile, $file_data, true)) { 874 | return FALSE; 875 | } else { 876 | //更新占用空间 877 | self::update_filesize_used($local_filepath); 878 | @unlink($local_filepath); 879 | unset($file_data); 880 | return TRUE; 881 | } 882 | } 883 | 884 | /** 885 | * Get a filename that is sanitized and unique for the given directory. 886 | * @uses self::$fs ,make sure the rest connection is available when you use this method! 887 | * @since 1.2.0 888 | * @param string $dir the remote dir 889 | * @param string $filename the base filename 890 | * @param mixed $unique_filename_callback Callback. 891 | * @return string New filename, if given wasn't unique. 892 | */ 893 | private static function unique_filename($dir, $filename) 894 | { 895 | // sanitize the file name before we begin processing 896 | $filename = sanitize_file_name($filename); 897 | 898 | // separate the filename into a name and extension 899 | $info = pathinfo($filename); 900 | $ext = !empty($info['extension']) ? '.' . $info['extension'] : ''; 901 | $name = basename($filename, $ext); 902 | 903 | // edge case: if file is named '.ext', treat as an empty name 904 | if ($name === $ext) 905 | $name = ''; 906 | 907 | // Increment the file number until we have a unique file to save in $dir. Use callback if supplied. 908 | $number = ''; 909 | 910 | // change '.ext' to lower case 911 | if ($ext && strtolower($ext) != $ext) { 912 | $ext2 = strtolower($ext); 913 | $filename2 = preg_replace('|' . preg_quote($ext) . '$|', $ext2, $filename); 914 | 915 | // check for both lower and upper case extension or image sub-sizes may be overwritten 916 | while (self::$fs->is_file($dir . "/$filename") || self::$fs->is_file($dir . "/$filename2")) { 917 | $new_number = $number + 1; 918 | $filename = str_replace("$number$ext", "$new_number$ext", $filename); 919 | $filename2 = str_replace("$number$ext2", "$new_number$ext2", $filename2); 920 | $number = $new_number; 921 | } 922 | return $filename2; 923 | } 924 | 925 | while (self::$fs->is_file($dir . "/$filename")) { 926 | if ('' == "$number$ext") 927 | $filename = $filename . ++$number . $ext; 928 | else 929 | $filename = str_replace("$number$ext", ++$number . $ext, $filename); 930 | } 931 | 932 | return $filename; 933 | } 934 | 935 | /** 936 | * 删除远程服务器上的单个文件 937 | * @static 938 | * @param $file 939 | * @return void 940 | */ 941 | public static function delete_remote_file($file) 942 | { 943 | $file = str_replace(self::$local_basepath, self::$http_remote_path, $file); 944 | if (strpos($file, self::$http_remote_path) !== 0) { 945 | $file = self::$rest_remote_path . '/' . $file; 946 | } 947 | 948 | self::setup_rest(); 949 | self::decrease_filesize_used(self::$fs, $file); 950 | self::$fs->rm($file); 951 | return ''; 952 | } 953 | 954 | /** 955 | * @see wp-admin/includes/scree.php Class Screen 956 | * add_contextual_help is deprecated 957 | * method to find current_screen: 958 | * function check_current_screen() { 959 | * if( !is_admin() ) return; 960 | * global $current_screen; 961 | * var_dump( $current_screen ); 962 | * } 963 | * add_action( 'admin_notices', 'check_current_screen' ); 964 | * @return void 965 | */ 966 | public static function add_my_contextual_help() 967 | { 968 | //WP_Screen id: 'settings_page_hacklog-remote-attachment/loader' 969 | $identifier = md5(HACKLOG_RA_UPYUN_LOADER); 970 | $current_screen_id = 'settings_page_' . $identifier; 971 | $text = '

' . __('Explanation of some Options', self::textdomain) . '

' . 972 | '

' . __('Remote base URL is the URL to your bucket root path.', self::textdomain) . '

' . 973 | '

' . __('rest Remote path is the relative path to your bucket main directory.Use "/" for bucket main(root) directory.You can use sub-directory Like wp-files', self::textdomain) . '

' . 974 | '

' . __('HTTP Remote path is the relative path to your HTTP main directory.Use "/" for HTTP main(root) directory.You can use sub-directory Like wp-files', self::textdomain) . '

' . 975 | '

' . __('For more information:', self::textdomain) . ' ' . __('Please visit the Plugin Home Page and Hacklog Remote Attachment home page.', self::textdomain) . '

'; 976 | $args = array( 977 | 'title' => sprintf(__("%s Help", self::textdomain), self::plugin_name), 978 | 'id' => $current_screen_id, 979 | 'content' => $text, 980 | 'callback' => false, 981 | ); 982 | $current_screen = get_current_screen(); 983 | $current_screen->add_help_tab($args); 984 | } 985 | 986 | /** 987 | * add menu page 988 | * @see http://codex.wordpress.org/Function_Reference/add_options_page 989 | * @static 990 | * @return void 991 | */ 992 | public static function plugin_menu() 993 | { 994 | $identifier = md5(HACKLOG_RA_UPYUN_LOADER); 995 | $option_page = add_options_page(__('Hacklog Remote Attachment Upyun Options', self::textdomain), __('Remote Attachment Upyun', self::textdomain), 'manage_options', $identifier, array(__CLASS__, 'plugin_options') 996 | ); 997 | // Adds my help tab when my admin page loads 998 | add_action('load-' . $option_page, array(__CLASS__, 'add_my_contextual_help')); 999 | } 1000 | 1001 | public static function show_message($message, $type = 'e') 1002 | { 1003 | if (empty($message)) 1004 | return; 1005 | $font_color = 'e' == $type ? '#FF0000' : '#4e9a06'; 1006 | $html = '

'; 1007 | $html .= "" . $message . ''; 1008 | $html .= '

'; 1009 | echo $html; 1010 | } 1011 | 1012 | /** 1013 | * option page 1014 | * @static 1015 | * @return void 1016 | */ 1017 | public static function plugin_options() 1018 | { 1019 | $msg = ''; 1020 | $error = ''; 1021 | 1022 | //update options 1023 | if (isset($_POST['submit'])) { 1024 | if (self::update_options()) { 1025 | $msg = __('Options updated.', self::textdomain); 1026 | } else { 1027 | $error = __('Nothing changed.', self::textdomain); 1028 | } 1029 | $credentials = array( 1030 | 'api_domain' => trim($_POST['rest_server']), 1031 | 'bucketname' => trim($_POST['bucketname']), 1032 | 'username' => trim($_POST['rest_user']), 1033 | 'password' => !empty($_POST['rest_pwd']) ? trim($_POST['rest_pwd']) : self::$rest_pwd, 1034 | 'form_api_secret' => !empty($_POST['form_api_secret']) ? trim($_POST['form_api_secret']) : self::$form_api_secret, 1035 | 'timeout' => trim($_POST['rest_timeout']), 1036 | 'ssl' => FALSE, 1037 | ); 1038 | if (self::connect_remote_server($credentials)) { 1039 | $msg .= __('Connected and Authenticated successfully.', self::textdomain); 1040 | } else { 1041 | $error_arr = self::raise_connection_error(); 1042 | $error .= $error_arr['error']; 1043 | } 1044 | } 1045 | 1046 | //tools 1047 | if (isset($_GET['hacklog_do'])) { 1048 | global $wpdb; 1049 | switch ($_GET['hacklog_do']) { 1050 | case 'replace_old_post_attach_url': 1051 | $orig_url = self::$local_baseurl; 1052 | $new_url = self::$remote_baseurl; 1053 | $sql = "UPDATE $wpdb->posts set post_content=replace(post_content,'$orig_url','$new_url')"; 1054 | break; 1055 | case 'recovery_post_attach_url': 1056 | $orig_url = self::$remote_baseurl; 1057 | $new_url = self::$local_baseurl; 1058 | $sql = "UPDATE $wpdb->posts set post_content=replace(post_content,'$orig_url','$new_url')"; 1059 | break; 1060 | } 1061 | if (($num_rows = $wpdb->query($sql)) > 0) { 1062 | $msg = sprintf('%d ' . __('posts has been updated.', self::textdomain), $num_rows); 1063 | $msg .= sprintf('%1$s
%2$s
', __('The following SQL statement was executeed:', self::textdomain), $sql); 1064 | } else { 1065 | $error = __('no posts been updated.', self::textdomain); 1066 | } 1067 | } 1068 | ?> 1069 |
1070 | 1071 |

1072 | 1076 |
1078 | 1079 | 1080 | 1082 | 1094 | 1095 | 1096 | 1098 | 1104 | 1105 | 1106 | 1107 | 1109 | 1115 | 1116 | 1117 | 1118 | 1120 | 1125 | 1126 | 1127 | 1128 | 1130 | 1136 | 1137 | 1138 | 1139 | 1141 | 1148 | 1149 | 1150 | 1153 | 1160 | 1161 | 1162 | 1163 | 1166 | 1173 | 1174 | 1175 | 1176 | 1179 | 1186 | 1187 | 1188 | 1189 | 1190 | 1193 | 1200 | 1201 | 1202 | 1205 | 1211 | 1212 | 1213 | 1214 | 1215 | 1217 | 1222 | 1223 | 1224 | 1225 | 1227 | 1233 | 1234 | 1235 | 1237 | 1244 | 1245 | 1246 | 1248 | 1255 | 1256 |
1083 | 1091 | 1093 |
1099 | 1101 | 1103 |
1108 | 1110 | 1112 | 1114 |
1121 | 1123 | 1124 |
1131 | 1133 | 1135 |
1142 | 1145 | form API features,you MUST enable this in your Upyun dashboard.', self::textdomain) ?> 1147 |
1152 | 1154 | 1157 | 1159 |
1167 | 1170 | 1172 |
1178 | 1180 | 1183 | jpg,jpeg,gif,png,doc,pdf,zip,rar,tar.gz,tar.bz2,7z', self::textdomain); ?> 1185 |
1192 | 1194 | 1197 | 1199 |
1204 | 1206 | 1209 | 1210 |
1218 | 1220 | 1221 |
1228 | 1230 | http://xxx.b0.upaiyun.com.', self::textdomain); ?> 1232 |
1238 | 1241 | /" for rest main(root) directory.You can use sub-directory Like wp-files', self::textdomain); ?> 1243 |
1249 | 1252 | /" for HTTP main(root) directory.You can use sub-directory Like wp-files', self::textdomain); ?> 1254 |
1257 |

1258 | 1260 |

1261 |
1262 |
1263 |
1264 |
1265 |

1266 | 1267 |

1268 | 1269 | get_bucket_usage(); 1272 | if (get_option(self::opt_space) != $total_size) { 1273 | update_option(self::opt_space, $total_size); 1274 | } 1275 | echo '' . self::human_size($total_size) . ''; 1276 | } else { 1277 | echo ''; 1278 | _e('Authentication failed OR Failed to connect to remote server!', self::textdomain); 1279 | echo ''; 1280 | } 1281 | ?> 1282 |

1283 | 1288 |
1289 |

Tools

1290 | 1291 |

1292 | DO NOT click the link below!", self::textdomain); ?> 1293 |

1294 | 1295 |

1296 | 1297 |

1298 | 1299 | 1301 |

1302 | 1303 |

1304 | 1305 |

1306 | 1307 | 1309 |

1310 |
1311 | ' . __('Check Update', self::textdomain) . ''); 1322 | return $links; 1323 | } 1324 | 1325 | } 1326 | -------------------------------------------------------------------------------- /languages/hacklog-remote-attachment-zh_CN.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monkey-wenjun/hacklog-remote-attachment-upyun/4c414acd25d6e566afcdf2b4d3976166847c5709/languages/hacklog-remote-attachment-zh_CN.mo -------------------------------------------------------------------------------- /languages/hacklog-remote-attachment-zh_CN.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Hacklog Remote Attachment\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2016-12-07 04:11+0800\n" 6 | "PO-Revision-Date: 2016-12-07 04:11+0800\n" 7 | "Last-Translator: 荒野无灯 \n" 8 | "Language-Team: 荒野无灯 \n" 9 | "Language: zh_CN\n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "X-Poedit-KeywordsList: _;gettext;gettext_noop;_e;__;esc_attr__\n" 14 | "X-Poedit-Basepath: ..\n" 15 | "X-Poedit-SourceCharset: UTF-8\n" 16 | "X-Generator: Poedit 1.8.11\n" 17 | "X-Poedit-SearchPath-0: .\n" 18 | 19 | #: filesystem/upyun.php:84 20 | msgid "api_domain is required" 21 | msgstr "" 22 | 23 | #: filesystem/upyun.php:89 24 | msgid "bucketname is required" 25 | msgstr "" 26 | 27 | #: filesystem/upyun.php:94 28 | msgid "username is required" 29 | msgstr "" 30 | 31 | #: filesystem/upyun.php:98 32 | msgid "password is required" 33 | msgstr "" 34 | 35 | #: includes/bootstrap_compatible.php:214 36 | msgid "Invalid plugin page" 37 | msgstr "" 38 | 39 | #: includes/bootstrap_compatible.php:217 40 | #, php-format 41 | msgid "Cannot load %s." 42 | msgstr "" 43 | 44 | #: includes/bootstrap_compatible.php:250 45 | msgid "You are not allowed to import." 46 | msgstr "" 47 | 48 | #: includes/bootstrap_compatible.php:273 49 | msgid "Import" 50 | msgstr "" 51 | 52 | #: includes/hacklogra_upyun.class.php:196 53 | #: includes/hacklogra_upyun.class.php:801 54 | msgid "upload file to remote server failed!" 55 | msgstr "上传文件到远程服务器失败!" 56 | 57 | #: includes/hacklogra_upyun.class.php:290 58 | msgid "Upyun internal Error!" 59 | msgstr "" 60 | 61 | #: includes/hacklogra_upyun.class.php:357 62 | msgid "Upload local file to Upyun server" 63 | msgstr "上传文件到又拍云服务器" 64 | 65 | #: includes/hacklogra_upyun.class.php:360 66 | msgid "Hacklog Remote Attachment Upyun" 67 | msgstr "Hacklog又拍云远程附件" 68 | 69 | #: includes/hacklogra_upyun.class.php:394 70 | msgid "Add media files from your computer" 71 | msgstr "" 72 | 73 | #: includes/hacklogra_upyun.class.php:396 74 | msgid "" 75 | "I advise you to upload images via click WordPress original add media button." 76 | msgstr "如果你要上传图片,我建议你使用左边的“添加媒体”按钮来上传。" 77 | 78 | #: includes/hacklogra_upyun.class.php:398 79 | msgid "This page was designed for uploading big files to UpYun Server." 80 | msgstr "这个页面主要设计用于上传大文件到又拍云服务器。" 81 | 82 | #: includes/hacklogra_upyun.class.php:430 83 | msgid "Save all changes" 84 | msgstr "" 85 | 86 | #: includes/hacklogra_upyun.class.php:693 87 | #, php-format 88 | msgid "Click here to setup the plugin options." 89 | msgstr "点击 这里 进行插件选项的设定." 90 | 91 | #: includes/hacklogra_upyun.class.php:971 92 | msgid "Explanation of some Options" 93 | msgstr "选项解释" 94 | 95 | #: includes/hacklogra_upyun.class.php:972 96 | msgid "Remote base URL is the URL to your bucket root path." 97 | msgstr " 远程基本URL 即到你的REST API服务器bucket根目录的URL" 98 | 99 | #: includes/hacklogra_upyun.class.php:973 100 | msgid "" 101 | "rest Remote path is the relative path to your bucket main " 102 | "directory.Use \"/\" for bucket main(root) directory.You can " 103 | "use sub-directory Like wp-files" 104 | msgstr "" 105 | "REST远程路径 即你用来保存附件的目录,相对于你的REST API " 106 | "bucket主目录,结尾不要带/,“/”表示bucket主目录" 107 | 108 | #: includes/hacklogra_upyun.class.php:974 109 | msgid "" 110 | "HTTP Remote path is the relative path to your HTTP main " 111 | "directory.Use \"/\" for HTTP main(root) directory.You can " 112 | "use sub-directory Like wp-files" 113 | msgstr "" 114 | "HTTP远程路径 即到你的HTTP主目录的相对路径,结尾不要" 115 | "带/,“/”表示HTTP服务器主目录。又拍云一般填写与REST远程路径 " 116 | "相同的内容即可。" 117 | 118 | #: includes/hacklogra_upyun.class.php:975 119 | msgid "For more information:" 120 | msgstr "更多帮助信息:" 121 | 122 | #: includes/hacklogra_upyun.class.php:975 123 | msgid "" 124 | "Please visit the Plugin Home Page and Hacklog Remote Attachment home page." 128 | msgstr "" 129 | 130 | #: includes/hacklogra_upyun.class.php:977 131 | #, php-format 132 | msgid "%s Help" 133 | msgstr "%s 帮助" 134 | 135 | #: includes/hacklogra_upyun.class.php:995 136 | #: includes/hacklogra_upyun.class.php:1071 137 | msgid "Hacklog Remote Attachment Upyun Options" 138 | msgstr "Hacklog 又拍云远程附件选项" 139 | 140 | #: includes/hacklogra_upyun.class.php:995 141 | msgid "Remote Attachment Upyun" 142 | msgstr "Hacklog 又拍云远程附件" 143 | 144 | #: includes/hacklogra_upyun.class.php:1025 145 | msgid "Options updated." 146 | msgstr "选项已经更新。" 147 | 148 | #: includes/hacklogra_upyun.class.php:1027 149 | msgid "Nothing changed." 150 | msgstr "没有任何改变。" 151 | 152 | #: includes/hacklogra_upyun.class.php:1039 153 | msgid "Connected and Authenticated successfully." 154 | msgstr "测试连接且认证成功。" 155 | 156 | #: includes/hacklogra_upyun.class.php:1062 157 | msgid "posts has been updated." 158 | msgstr "篇日志内容已经被更新。" 159 | 160 | #: includes/hacklogra_upyun.class.php:1063 161 | msgid "The following SQL statement was executeed:" 162 | msgstr "以下SQL语句被成功执行:" 163 | 164 | #: includes/hacklogra_upyun.class.php:1065 165 | msgid "no posts been updated." 166 | msgstr "没有日志被更新。" 167 | 168 | #: includes/hacklogra_upyun.class.php:1080 169 | msgid "REST API server" 170 | msgstr "REST API 服务器" 171 | 172 | #: includes/hacklogra_upyun.class.php:1092 173 | msgid "the IP or domain name of remote file server." 174 | msgstr "" 175 | "远程服务器的IP或域名,请根据你的WP服务器所处网络进行选择,如果不清楚,可以选择" 176 | "自动判断。" 177 | 178 | #: includes/hacklogra_upyun.class.php:1096 179 | msgid "REST API server port" 180 | msgstr "REST API服务器端口,目前填写80即可" 181 | 182 | #: includes/hacklogra_upyun.class.php:1102 183 | msgid "the listenning port of remote rest server.Generally it is 80." 184 | msgstr "远程API服务器的监听端口.通常是80" 185 | 186 | #: includes/hacklogra_upyun.class.php:1107 187 | msgid "bucketname" 188 | msgstr "空间名称" 189 | 190 | #: includes/hacklogra_upyun.class.php:1113 191 | msgid "the bucketname you want to store your files to." 192 | msgstr "你用于存储文件的空间名称。" 193 | 194 | #: includes/hacklogra_upyun.class.php:1118 195 | msgid "REST API username" 196 | msgstr "操作员用户名" 197 | 198 | #: includes/hacklogra_upyun.class.php:1123 199 | msgid "the REST API username." 200 | msgstr "又拍云存储上的操作员用户名。" 201 | 202 | #: includes/hacklogra_upyun.class.php:1128 203 | msgid "REST API password" 204 | msgstr "操作员用户密码" 205 | 206 | #: includes/hacklogra_upyun.class.php:1134 207 | msgid "" 208 | "the API user 's password.will not be displayed here since filled and updated." 209 | msgstr "操作员密码。更新之后这里不会显示。" 210 | 211 | #: includes/hacklogra_upyun.class.php:1139 212 | msgid "form api secret" 213 | msgstr "表单API密钥" 214 | 215 | #: includes/hacklogra_upyun.class.php:1146 216 | msgid "" 217 | "the form API secret.Be aware that if you want to use the form API " 218 | "features,you MUST enable this in your Upyun dashboard." 219 | msgstr "" 220 | "表单API密钥。(没有开表单API功能的不用设置)如果你要使用表单API功能上传文件,注意在又拍云空间管理中启用此功能。" 222 | 223 | #: includes/hacklogra_upyun.class.php:1151 224 | msgid "form API timeout(s)" 225 | msgstr "表单API授权超时" 226 | 227 | #: includes/hacklogra_upyun.class.php:1158 228 | msgid "" 229 | "form API authorization timeout.the max authorized time (calculated in " 230 | "seconds) when upload file via form API.It depends on your computer's network " 231 | "condition." 232 | msgstr "" 233 | "表单API授权超时,即通过表单API功能上传时的授权时长限制。这取决于你的计算机所" 234 | "在的网络环境。" 235 | 236 | #: includes/hacklogra_upyun.class.php:1164 237 | msgid "form API content max length(MiB)" 238 | msgstr "表单API内容最大长度(MiB)" 239 | 240 | #: includes/hacklogra_upyun.class.php:1171 241 | #, php-format 242 | msgid "" 243 | "the max file size (calculated in MiB) when upload file via form API." 244 | "Currently,Upyun 's limitation is %d MiB" 245 | msgstr "" 246 | "通过表单API上传时最大允许上传的文件大小(以M计算)。目前又拍云的限制是 %d MiB." 247 | 248 | #: includes/hacklogra_upyun.class.php:1177 249 | msgid "form API allowd ext" 250 | msgstr "表单API允许文件后缀" 251 | 252 | #: includes/hacklogra_upyun.class.php:1184 253 | msgid "" 254 | "form API allowed file extension.For example: jpg,jpeg,gif,png,doc," 255 | "pdf,zip,rar,tar.gz,tar.bz2,7z" 256 | msgstr "" 257 | "通过表单API上传时允许的文件后缀,如 jpg,jpeg,gif,png,doc,pdf,zip,rar," 258 | "tar.gz,tar.bz2,7z" 259 | 260 | #: includes/hacklogra_upyun.class.php:1191 261 | msgid "anti leech token key" 262 | msgstr "防盗链TOKEN密钥" 263 | 264 | #: includes/hacklogra_upyun.class.php:1198 265 | msgid "the anti leech token key your set in upyun panel" 266 | msgstr "你在又拍云\"空间设置\"里面设定的防盗链密钥,不启用请勿填写。" 267 | 268 | #: includes/hacklogra_upyun.class.php:1203 269 | msgid "anti leech timeout(s)" 270 | msgstr "防盗链超时(s)" 271 | 272 | #: includes/hacklogra_upyun.class.php:1209 273 | msgid "anti leech timeout" 274 | msgstr "" 275 | "防盗链超时(没有开启防盗链的不用设置)。即从网页开始显示到链接超时的时间间隔。" 276 | "超时以后,链接便会失效。如果是比较大的文件,如音乐、电影等,你必须考虑用户播" 277 | "放此文件或下载此文件需要多长时间,超时以后链接将会自动失效。" 278 | 279 | #: includes/hacklogra_upyun.class.php:1215 280 | msgid "rest timeout(s)" 281 | msgstr "REST连接超时(s)" 282 | 283 | #: includes/hacklogra_upyun.class.php:1220 284 | msgid "rest connection timeout." 285 | msgstr "RESET API连接超时设置" 286 | 287 | #: includes/hacklogra_upyun.class.php:1225 288 | msgid "Remote base URL" 289 | msgstr "远程基本URL" 290 | 291 | #: includes/hacklogra_upyun.class.php:1231 292 | msgid "" 293 | "Remote base URL,the URL to your bucket root path.for example: http://" 294 | "xxx.b0.upaiyun.com." 295 | msgstr "" 296 | "远程基本URL,即到你的bucket根目录的URL,结尾不要带/。如: " 297 | "http://xxx.b0.upaiyun.com" 298 | 299 | #: includes/hacklogra_upyun.class.php:1235 300 | msgid "rest Remote path" 301 | msgstr "REST空间远程路径" 302 | 303 | #: includes/hacklogra_upyun.class.php:1242 304 | msgid "" 305 | "the relative path to your bucket main directory.Use \"/\" " 306 | "for rest main(root) directory.You can use sub-directory Like wp-" 307 | "files" 308 | msgstr "" 309 | "REST远程路径即你用来保存附件的目录,相对于你的bucket主目录," 310 | "结尾不要带/,“/”表示bucket主目录" 311 | 312 | #: includes/hacklogra_upyun.class.php:1246 313 | msgid "HTTP Remote path" 314 | msgstr "HTTP远程路径" 315 | 316 | #: includes/hacklogra_upyun.class.php:1253 317 | msgid "" 318 | "the relative path to your HTTP main directory.Use \"/\" for " 319 | "HTTP main(root) directory.You can use sub-directory Like wp-files" 321 | msgstr "" 322 | "HTTP远程路径 即到你的HTTP主目录的相对路径,结尾不要" 323 | "带/,“/”表示HTTP服务器主目录。又拍云一般填写与REST远程路径 " 324 | "相同的内容即可。" 325 | 326 | #: includes/hacklogra_upyun.class.php:1259 327 | msgid "Save Options" 328 | msgstr "保存选项" 329 | 330 | #: includes/hacklogra_upyun.class.php:1265 331 | msgid "Hacklog Remote Attachment UpYun Status" 332 | msgstr "Hacklog 又拍云远程附件状态" 333 | 334 | #: includes/hacklogra_upyun.class.php:1268 335 | msgid "Space used on remote server:" 336 | msgstr "远程服务器上的附件已用空间:" 337 | 338 | #: includes/hacklogra_upyun.class.php:1278 339 | msgid "Authentication failed OR Failed to connect to remote server!" 340 | msgstr "认证失败或无法连接远程服务器!" 341 | 342 | #: includes/hacklogra_upyun.class.php:1291 343 | msgid "warning:" 344 | msgstr "敬告:" 345 | 346 | #: includes/hacklogra_upyun.class.php:1292 347 | msgid "" 348 | "if you haven't moved all your attachments OR dont't know what below means," 349 | "please DO NOT click the link below!" 350 | msgstr "" 351 | "如果你没有移动附件或你不清楚下面说的是什么意思,请不要 点击" 352 | "下面的链接!" 353 | 354 | #: includes/hacklogra_upyun.class.php:1295 355 | msgid "Move" 356 | msgstr "" 357 | 358 | #: includes/hacklogra_upyun.class.php:1298 359 | msgid "" 360 | "if you have moved all your attachments to the remote server,then you can " 361 | "click" 362 | msgstr "如果你已经把所有的附件移动到了远程服务器上,你可以点击" 363 | 364 | #: includes/hacklogra_upyun.class.php:1299 365 | #: includes/hacklogra_upyun.class.php:1307 366 | msgid "" 367 | "Are your sure to do this?Make sure you have backuped your database tables." 368 | msgstr "你确定要这样做吗?请确保在执行此操作前已经备份好了你的数据库。" 369 | 370 | #: includes/hacklogra_upyun.class.php:1300 371 | #: includes/hacklogra_upyun.class.php:1308 372 | msgid "here" 373 | msgstr "这里" 374 | 375 | #: includes/hacklogra_upyun.class.php:1300 376 | #: includes/hacklogra_upyun.class.php:1308 377 | msgid " to update the database." 378 | msgstr "来更新数据库。" 379 | 380 | #: includes/hacklogra_upyun.class.php:1303 381 | msgid "Recovery" 382 | msgstr "" 383 | 384 | #: includes/hacklogra_upyun.class.php:1306 385 | msgid "" 386 | "if you have moved all your attachments from the remote server to local " 387 | "server,then you can click" 388 | msgstr "如果你已经把所有附件从远程服务器转移到了本地服务器,请点击" 389 | 390 | #: includes/hacklogra_upyun.class.php:1321 391 | msgid "Check Update" 392 | msgstr "检查更新" 393 | 394 | #: upload.php:30 395 | msgid "You do not have permission to upload files." 396 | msgstr "sorry~~您没有上传文件的权限。" 397 | 398 | #: upload.php:45 upload.php:49 399 | msgid "You are not allowed to be here" 400 | msgstr "" 401 | 402 | #: upload.php:160 403 | msgid "Saved." 404 | msgstr "" 405 | 406 | #: upload.php:227 upload.php:229 407 | msgid "Upload" 408 | msgstr "上传" 409 | 410 | #: upload.php:230 411 | msgid "Cancel" 412 | msgstr "取消" 413 | 414 | #: upload.php:244 415 | #, php-format 416 | msgid "Maximum upload file size: %d%s." 417 | msgstr "允许上传的文件最大为:%d%s." 418 | 419 | #: upload.php:247 420 | msgid "" 421 | "Your browser has some limitations uploading large files with the multi-file " 422 | "uploader. Please use the browser uploader for files over 100MB." 423 | msgstr "" 424 | 425 | #: upload.php:254 426 | msgid "via UpYun Form API" 427 | msgstr "通过又拍云表单API功能上传" 428 | 429 | #~ msgid "" 430 | #~ "Please visit the Plugin Home Page and Hacklog Remote Attachment home page." 433 | #~ msgstr "" 434 | #~ "请访问 插件主页" 435 | #~ "Hacklog " 436 | #~ "Remote Attachment 主页。" 437 | 438 | #~ msgid "Failed to connect to remote server!Could not resolve the hostname." 439 | #~ msgstr "连接远程服务器失败!无法解析主机名。" 440 | 441 | #~ msgid "failed to make dir on remote server!Please check your permissions." 442 | #~ msgstr "在远程服务器创建目录失败!请检查API接口用户权限。" 443 | 444 | #~ msgid "" 445 | #~ "rest Remote path is the relative path to your bucket " 446 | #~ "main directory.Use \".\" for bucket main(root) directory." 447 | #~ "You can use sub-directory Like wp-files" 448 | #~ msgstr "" 449 | #~ "REST远程路径 即你用来保存附件的目录,相对于你的REST API " 450 | #~ "bucket主目录,结尾不要带/,“.”表示bucket主目录" 451 | 452 | #~ msgid "" 453 | #~ "HTTP Remote path is the relative path to your HTTP main " 454 | #~ "directory.Use \".\" for HTTP main(root) directory.You " 455 | #~ "can use sub-directory Like wp-files" 456 | #~ msgstr "" 457 | #~ "HTTP远程路径 即到你的HTTP主目录的相对路径,结尾不要" 458 | #~ "带/,“.”表示HTTP服务器主目录。又拍云一般填写与REST远程路径 相同的内容即可。" 460 | 461 | #~ msgid "" 462 | #~ "the relative path to your bucket main directory.Use \"." 463 | #~ "\" for rest main(root) directory.You can use sub-directory Like " 464 | #~ "wp-files" 465 | #~ msgstr "" 466 | #~ "REST远程路径即你用来保存附件的目录,相对于你的bucket主目" 467 | #~ "录,结尾不要带/,“.”表示bucket主目录" 468 | 469 | #~ msgid "" 470 | #~ "the relative path to your HTTP main directory.Use \".\" " 471 | #~ "for HTTP main(root) directory.You can use sub-directory Like wp-" 472 | #~ "files" 473 | #~ msgstr "" 474 | #~ "HTTP远程路径,到你的HTTP主目录的相对路径,结尾不要" 475 | #~ "带/,“.”表示HTTP服务器主目录" 476 | 477 | #~ msgid "the bucketname." 478 | #~ msgstr "又拍云存储上你创建的空间名称" 479 | 480 | #~ msgid "the password." 481 | #~ msgstr "又拍云存储上的操作员用户密码。(这里不会显示)" 482 | 483 | #~ msgid "Hacklog Remote Attachment Options" 484 | #~ msgstr "Hacklog远程附件选项" 485 | 486 | #~ msgid "rest server" 487 | #~ msgstr "REST API服务器" 488 | 489 | #~ msgid "" 490 | #~ "the Remote path is the directory which you save " 491 | #~ "attachment under it and it is relative to your Ftp root path." 492 | #~ msgstr "" 493 | #~ "远程路径即你用来保存附件的目录,相对于你的Ftp主目录,主目" 494 | #~ "录请用点号." 495 | 496 | #~ msgid "the sub dir.Like wp-files" 497 | #~ msgstr "" 498 | #~ "远程路径即你用来保存附件的目录,相对于你的Ftp主目录,结尾" 499 | #~ "不要带/,“.”表示FTP主目录,如 wp-" 500 | #~ "files" 501 | 502 | #~ msgid "" 503 | #~ "failed to make dir on remote server!Pleas check your FTP file " 505 | #~ "permissions" 506 | #~ msgstr "" 507 | #~ "在远程服务器创建目录失败!请检测FTP 文件权限" 509 | -------------------------------------------------------------------------------- /loader.php: -------------------------------------------------------------------------------- 1 | 15 | * @link http://ihacklog.com 16 | * @copyright Copyright (C) 2012 荒野无灯 17 | * @license http://www.gnu.org/licenses/ 18 | */ 19 | 20 | /* 21 | Copyright 2012 荒野无灯 22 | 23 | This program is free software; you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation; either version 2 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program; if not, write to the Free Software 35 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 36 | */ 37 | if (! defined ( 'ABSPATH' )) { 38 | die ( 'What are you doing?' ); 39 | } 40 | 41 | //the Hacklog Remote Attachment plugin maybe loaded after this plugin,so,we can only remind the user. 42 | function check_hacklog_ra_upyun_compability() 43 | { 44 | if (class_exists ( 'hacklogra' )) 45 | { 46 | add_action ( 'admin_notices', create_function ( '', 'echo "

Error: you have already activated Hacklog Remote Attachment,Please deactivate it and then activate this plugin(Hacklog Remote Attachment Upyun).

";' ) ); 47 | } 48 | } 49 | add_action('admin_init','check_hacklog_ra_upyun_compability'); 50 | 51 | 52 | define ( 'HACKLOG_RA_UPYUN_LOADER', __FILE__ ); 53 | require plugin_dir_path ( __FILE__ ) . '/includes/hacklogra_upyun.class.php'; 54 | new hacklogra_upyun (); 55 | -------------------------------------------------------------------------------- /screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monkey-wenjun/hacklog-remote-attachment-upyun/4c414acd25d6e566afcdf2b4d3976166847c5709/screenshot-1.png -------------------------------------------------------------------------------- /screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monkey-wenjun/hacklog-remote-attachment-upyun/4c414acd25d6e566afcdf2b4d3976166847c5709/screenshot-2.png -------------------------------------------------------------------------------- /upload.php: -------------------------------------------------------------------------------- 1 | 6 | * @link http://ihacklog.com 7 | * @copyright Copyright (C) 2012 荒野无灯 8 | * @license http://www.gnu.org/licenses/ 9 | * @description 10 | * upload file via UpYun form API. 11 | */ 12 | 13 | 14 | define( 'IFRAME_REQUEST' , true ); 15 | 16 | /** Load WordPress Administration Bootstrap */ 17 | $bootstrap_file = dirname(__FILE__). '/includes/bootstrap_compatible.php' ; 18 | if (file_exists( $bootstrap_file )) 19 | { 20 | require $bootstrap_file; 21 | } 22 | else 23 | { 24 | echo '

Failed to load bootstrap.

'; 25 | exit; 26 | } 27 | 28 | 29 | if (!current_user_can('upload_files')) 30 | wp_die(__('You do not have permission to upload files.')); 31 | 32 | wp_enqueue_script('plupload-handlers'); 33 | wp_enqueue_script('image-edit'); 34 | wp_enqueue_script('set-post-thumbnail' ); 35 | wp_enqueue_style('imgareaselect'); 36 | 37 | @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset')); 38 | 39 | // IDs should be integers 40 | $ID = isset($ID) ? (int) $ID : 0; 41 | $post_id = isset($_REQUEST['post_id'])? (int) $_REQUEST['post_id'] : 0; 42 | 43 | // Require an ID for the edit screen 44 | if ( isset($action) && $action == 'edit' && !$ID ) 45 | wp_die(__("You are not allowed to be here")); 46 | 47 | if($post_id <= 0) 48 | { 49 | wp_die(__("You are not allowed to be here")); 50 | } 51 | else 52 | { 53 | 54 | add_filter('media_upload_tabs', 'hacklogra_upyun_upload_tags'); 55 | // upload type: image, video, file, ..? 56 | if ( isset($_GET['type']) ) 57 | $type = strval($_GET['type']); 58 | else 59 | $type = apply_filters('media_upload_default_type', 'file'); 60 | 61 | // tab: gallery, library, or type-specific 62 | if ( isset($_GET['tab']) ) 63 | $tab = strval($_GET['tab']); 64 | else 65 | $tab = apply_filters('media_upload_default_tab', 'type'); 66 | 67 | $body_id = 'media-upload'; 68 | 69 | if( $tab == 'type') 70 | { 71 | hacklogra_upyun_media_upload_handler(); 72 | } 73 | else 74 | { 75 | // let the action code decide how to handle the request 76 | if ( $tab == 'type_url' || !array_key_exists( $tab , media_upload_tabs() ) ) 77 | { 78 | do_action("media_upload_$type"); 79 | } 80 | else 81 | { 82 | do_action("media_upload_$tab"); 83 | } 84 | } 85 | 86 | } 87 | 88 | 89 | /** 90 | * {@internal Missing Short Description}} 91 | * 92 | * @since 1.4.0 93 | * 94 | * @return unknown 95 | */ 96 | function hacklogra_upyun_media_upload_handler() 97 | { 98 | global $is_iphone; 99 | 100 | $errors = array(); 101 | $id = 0; 102 | 103 | if ( isset($_GET['code']) && isset($_GET['message']) && isset($_GET['url']) && isset($_GET['time']) ) 104 | { 105 | $id = hacklogra_upyun::handle_form_api_upload($_REQUEST['post_id'], $post_data = array() ); 106 | unset($_FILES); 107 | if ( is_wp_error($id) ) 108 | { 109 | $errors['upload_error'] = $id; 110 | $id = false; 111 | } 112 | } 113 | 114 | if ( !empty($_POST['insertonlybutton']) ) 115 | { 116 | $src = $_POST['src']; 117 | if ( !empty($src) && !strpos($src, '://') ) 118 | $src = "http://$src"; 119 | 120 | if ( isset( $_POST['media_type'] ) && 'image' != $_POST['media_type'] ) { 121 | $title = esc_html( stripslashes( $_POST['title'] ) ); 122 | if ( empty( $title ) ) 123 | $title = esc_html( basename( $src ) ); 124 | 125 | if ( $title && $src ) 126 | $html = "$title"; 127 | 128 | $type = 'file'; 129 | if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) ) 130 | && ( 'audio' == $ext_type || 'video' == $ext_type ) ) 131 | $type = $ext_type; 132 | 133 | $html = apply_filters( $type . '_send_to_editor_url', $html, esc_url_raw( $src ), $title ); 134 | } else { 135 | $align = ''; 136 | $alt = esc_attr( stripslashes( $_POST['alt'] ) ); 137 | if ( isset($_POST['align']) ) { 138 | $align = esc_attr( stripslashes( $_POST['align'] ) ); 139 | $class = " class='align$align'"; 140 | } 141 | if ( !empty($src) ) 142 | $html = "$alt"; 143 | 144 | $html = apply_filters( 'image_send_to_editor_url', $html, esc_url_raw( $src ), $alt, $align ); 145 | } 146 | 147 | return media_send_to_editor($html); 148 | } 149 | 150 | if ( !empty($_POST) ) { 151 | $return = media_upload_form_handler(); 152 | 153 | if ( is_string($return) ) 154 | return $return; 155 | if ( is_array($return) ) 156 | $errors = $return; 157 | } 158 | 159 | if ( isset($_POST['save']) ) { 160 | $errors['upload_notice'] = __('Saved.'); 161 | return media_upload_gallery(); 162 | } 163 | 164 | if ( isset($_GET['tab']) && $_GET['tab'] == 'type_url' ) { 165 | $type = 'image'; 166 | if ( isset( $_GET['type'] ) && in_array( $_GET['type'], array( 'video', 'audio', 'file' ) ) ) 167 | $type = $_GET['type']; 168 | return wp_iframe( 'media_upload_type_url_form', $type, $errors, $id ); 169 | } 170 | 171 | if ( $is_iphone ) 172 | return wp_iframe( 'media_upload_type_url_form', 'image', $errors, $id ); 173 | else 174 | return wp_iframe( array('hacklogra_upyun', 'media_upload_type_form_upyun'), 'file', $errors, $id ); 175 | } 176 | 177 | 178 | function hacklogra_upyun_media_upload_form( $errors = null ) 179 | { 180 | global $type, $tab, $pagenow, $is_IE, $is_opera, $is_iphone; 181 | 182 | if ( $is_iphone ) 183 | return; 184 | 185 | $post_id = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : 0; 186 | $_type = isset($type) ? $type : ''; 187 | $_tab = isset($tab) ? $tab : ''; 188 | 189 | $upload_size_unit = $max_upload_size = Filesystem_Upyun::FORM_API_MAX_CONTENT_LENGTH; 190 | $sizes = array( 'KB', 'MB', 'GB' ); 191 | 192 | for ( $u = -1; $upload_size_unit > 1024 && $u < count( $sizes ) - 1; $u++ ) { 193 | $upload_size_unit /= 1024; 194 | } 195 | 196 | if ( $u < 0 ) { 197 | $upload_size_unit = 0; 198 | $u = 0; 199 | } else { 200 | $upload_size_unit = (int) $upload_size_unit; 201 | } 202 | ?> 203 | 204 |
205 |
213 |
214 | get_error_message(); 218 | $location_href = plugins_url('upload.php?post_id=' . $post_id .'&TB_iframe=1&width=640&height=451', __FILE__); 219 | echo 'Retry'; 220 | } 221 | ?> 222 |
223 | 224 | 225 |
226 |

227 | 228 | 229 | 230 | 231 |

232 |
233 |
234 | 235 | 242 | 243 | 244 | 245 | 100 * 1024 * 1024 ) { ?> 247 | 248 | 259 | -------------------------------------------------------------------------------- /vendor/upyun.class.php: -------------------------------------------------------------------------------- 1 | _bucketname = $bucketname; 49 | $this->_username = $username; 50 | $this->_password = md5($password); 51 | $this->_timeout = $timeout; 52 | 53 | $this->endpoint = is_null($endpoint) ? self::ED_AUTO : $endpoint; 54 | } 55 | 56 | /** 57 | * 获取当前SDK版本号 58 | */ 59 | public function version() 60 | { 61 | return self::VERSION; 62 | } 63 | 64 | /** 65 | * 创建目录 66 | * @param $path string 路径 67 | * @param $auto_mkdir bool 是否自动创建父级目录,最多10层次 68 | * 69 | * @return mixed 70 | */ 71 | public function makeDir($path, $auto_mkdir = true) 72 | { 73 | $headers = array('Folder' => 'true'); 74 | if ($auto_mkdir) $headers['Mkdir'] = 'true'; 75 | return $this->_do_request('PUT', $path, $headers); 76 | } 77 | 78 | /** 79 | * 删除目录和文件 80 | * @param string $path 路径 81 | * 82 | * @return boolean 83 | */ 84 | public function delete($path) 85 | { 86 | return $this->_do_request('DELETE', $path); 87 | } 88 | 89 | 90 | /** 91 | * 上传文件 92 | * @param string $path 存储路径 93 | * @param mixed $file 需要上传的文件,可以是文件流或者文件内容 94 | * @param boolean $auto_mkdir 自动创建目录 95 | * @param array $opts 可选参数 96 | * @return mixed|null 97 | */ 98 | public function writeFile($path, $file, $auto_mkdir = true, $opts = NULL) 99 | { 100 | if (is_null($opts)) $opts = array(); 101 | 102 | if (!is_null($this->_content_md5)) $opts[self::CONTENT_MD5] = $this->_content_md5; 103 | if (!is_null($this->_file_secret)) $opts[self::CONTENT_SECRET] = $this->_file_secret; 104 | 105 | if ($auto_mkdir === true) $opts['Mkdir'] = 'true'; 106 | 107 | return $this->_do_request('PUT', $path, $opts, $file); 108 | } 109 | 110 | /** 111 | * 下载文件 112 | * @param string $path 文件路径 113 | * @param mixed $file_handle 114 | * 115 | * @return mixed 116 | */ 117 | public function readFile($path, $file_handle = NULL) 118 | { 119 | return $this->_do_request('GET', $path, NULL, NULL, $file_handle); 120 | } 121 | 122 | /** 123 | * 获取目录文件列表 124 | * 125 | * @param string $path 查询路径 126 | * 127 | * @return mixed 128 | */ 129 | public function getList($path = '/') 130 | { 131 | $rsp = $this->_do_request('GET', $path); 132 | 133 | $list = array(); 134 | if ($rsp) { 135 | $rsp = explode("\n", $rsp); 136 | foreach ($rsp as $item) { 137 | @list($name, $type, $size, $time) = explode("\t", trim($item)); 138 | if (!empty($time)) { 139 | $type = ($type == 'N') ? 'file' : 'folder'; 140 | } 141 | 142 | $item = array( 143 | 'name' => $name, 144 | 'type' => $type, 145 | 'size' => intval($size), 146 | 'time' => intval($time), 147 | ); 148 | array_push($list, $item); 149 | } 150 | } 151 | 152 | return $list; 153 | } 154 | 155 | /** 156 | * 获取文件、目录信息 157 | * 158 | * @param string $path 路径 159 | * 160 | * @return mixed 161 | */ 162 | public function getFileInfo($path) 163 | { 164 | $rsp = $this->_do_request('HEAD', $path); 165 | return $rsp; 166 | } 167 | 168 | /** 169 | * 获取空间使用情况 170 | * @param string $bucket 171 | * @return mixed 172 | * @throws UpYunAuthorizationException 173 | * @throws UpYunException 174 | * @throws UpYunForbiddenException 175 | * @throws UpYunNotAcceptableException 176 | * @throws UpYunNotFoundException 177 | * @throws UpYunServiceUnavailable 178 | */ 179 | public function getFolderUsage($bucket = '/') 180 | { 181 | return $this->_do_request('GET', "/{$this->_bucketname}/?usage"); 182 | } 183 | 184 | /** 185 | * 获取空间存储使用量,单位 byte 186 | */ 187 | public function getBucketUsage() 188 | { 189 | return $this->getFolderUsage('/'); 190 | } 191 | 192 | public function getXRequestId() 193 | { 194 | return $this->x_request_id; 195 | } 196 | 197 | /** 198 | * 设置文件访问密钥 199 | */ 200 | public function setFileSecret($str) 201 | { 202 | $this->_file_secret = $str; 203 | } 204 | 205 | /** 206 | * 这是文件 md5 校验值 207 | */ 208 | public function setContentMd5($str) 209 | { 210 | $this->_content_md5 = $str; 211 | } 212 | 213 | /** 214 | * 连接签名方法 215 | * @param $method string 请求方式 {GET, POST, PUT, DELETE} 216 | * @return string 签名字符串 217 | */ 218 | private function sign($method, $uri, $date, $length) 219 | { 220 | //$uri = urlencode($uri); 221 | $sign = "{$method}&{$uri}&{$date}&{$length}&{$this->_password}"; 222 | return 'UpYun ' . $this->_username . ':' . md5($sign); 223 | } 224 | 225 | /** 226 | * HTTP REQUEST 封装 227 | * @param string $method HTTP REQUEST方法,包括PUT、POST、GET、OPTIONS、DELETE 228 | * @param string $path 除Bucketname之外的请求路径,包括get参数 229 | * @param array $headers 请求需要的特殊HTTP HEADERS 230 | * @param array $body 需要POST发送的数据 231 | * @param null $file_handle 232 | * @return mixed 233 | * @throws UpYunAuthorizationException 234 | * @throws UpYunException 235 | * @throws UpYunForbiddenException 236 | * @throws UpYunNotAcceptableException 237 | * @throws UpYunNotFoundException 238 | * @throws UpYunServiceUnavailable 239 | */ 240 | protected function _do_request($method, $path, $headers = NULL, $body = NULL, $file_handle = NULL) 241 | { 242 | $uri = "/{$this->_bucketname}{$path}"; 243 | $ch = curl_init("http://{$this->endpoint}{$uri}"); 244 | 245 | $_headers = array('Expect:'); 246 | if (!is_null($headers) && is_array($headers)) { 247 | foreach ($headers as $k => $v) { 248 | array_push($_headers, "{$k}: {$v}"); 249 | } 250 | } 251 | 252 | $length = 0; 253 | $date = gmdate('D, d M Y H:i:s \G\M\T'); 254 | 255 | if (!is_null($body)) { 256 | if (is_resource($body)) { 257 | fseek($body, 0, SEEK_END); 258 | $length = ftell($body); 259 | fseek($body, 0); 260 | 261 | array_push($_headers, "Content-Length: {$length}"); 262 | curl_setopt($ch, CURLOPT_INFILE, $body); 263 | curl_setopt($ch, CURLOPT_INFILESIZE, $length); 264 | } else { 265 | $length = @strlen($body); 266 | array_push($_headers, "Content-Length: {$length}"); 267 | curl_setopt($ch, CURLOPT_POSTFIELDS, $body); 268 | } 269 | } else { 270 | array_push($_headers, "Content-Length: {$length}"); 271 | } 272 | 273 | array_push($_headers, "Authorization: {$this->sign($method, $uri, $date, $length)}"); 274 | array_push($_headers, "Date: {$date}"); 275 | 276 | curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers); 277 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout); 278 | curl_setopt($ch, CURLOPT_HEADER, 1); 279 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 280 | //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 281 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); 282 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); 283 | 284 | if ($method == 'PUT' || $method == 'POST') { 285 | curl_setopt($ch, CURLOPT_POST, 1); 286 | } else { 287 | curl_setopt($ch, CURLOPT_POST, 0); 288 | } 289 | 290 | if ($method == 'GET' && is_resource($file_handle)) { 291 | curl_setopt($ch, CURLOPT_HEADER, 0); 292 | curl_setopt($ch, CURLOPT_FILE, $file_handle); 293 | } 294 | 295 | if ($method == 'HEAD') { 296 | curl_setopt($ch, CURLOPT_NOBODY, true); 297 | } 298 | 299 | $response = curl_exec($ch); 300 | $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 301 | 302 | if ($http_code == 0) throw new UpYunException('Connection Failed', $http_code); 303 | 304 | curl_close($ch); 305 | 306 | $header_string = ''; 307 | $body = ''; 308 | 309 | if ($method == 'GET' && is_resource($file_handle)) { 310 | $header_string = ''; 311 | $body = $response; 312 | } else { 313 | list($header_string, $body) = explode("\r\n\r\n", $response, 2); 314 | } 315 | $this->setXRequestId($header_string); 316 | if ($http_code == 200) { 317 | if ($method == 'GET' && is_null($file_handle)) { 318 | return $body; 319 | } else { 320 | $data = $this->_getHeadersData($header_string); 321 | return count($data) > 0 ? $data : true; 322 | } 323 | } else { 324 | $message = $this->_getErrorMessage($header_string); 325 | if (is_null($message) && $method == 'GET' && is_resource($file_handle)) { 326 | $message = 'File Not Found'; 327 | } 328 | switch ($http_code) { 329 | case 401: 330 | throw new UpYunAuthorizationException($message); 331 | break; 332 | case 403: 333 | throw new UpYunForbiddenException($message); 334 | break; 335 | case 404: 336 | throw new UpYunNotFoundException($message); 337 | break; 338 | case 406: 339 | throw new UpYunNotAcceptableException($message); 340 | break; 341 | case 503: 342 | throw new UpYunServiceUnavailable($message); 343 | break; 344 | default: 345 | throw new UpYunException($message, $http_code); 346 | } 347 | } 348 | } 349 | 350 | /** 351 | * 处理HTTP HEADERS中返回的自定义数据 352 | * 353 | * @param string $text header字符串 354 | * 355 | * @return array 356 | */ 357 | private function _getHeadersData($text) 358 | { 359 | $headers = explode("\r\n", $text); 360 | $items = array(); 361 | foreach ($headers as $header) { 362 | $header = trim($header); 363 | if (stripos($header, 'x-upyun') !== False) { 364 | list($k, $v) = explode(':', $header); 365 | $items[trim($k)] = in_array(substr($k, 8, 5), array('width', 'heigh', 'frame')) ? intval($v) : trim($v); 366 | } 367 | } 368 | return $items; 369 | } 370 | 371 | /** 372 | * 获取返回的错误信息 373 | * 374 | * @param string $header_string 375 | * 376 | * @return mixed 377 | */ 378 | private function _getErrorMessage($header_string) 379 | { 380 | list($status, $stash) = explode("\r\n", $header_string, 2); 381 | list($v, $code, $message) = explode(" ", $status, 3); 382 | return $message . " X-Request-Id: " . $this->getXRequestId(); 383 | } 384 | 385 | private function setXRequestId($header_string) 386 | { 387 | preg_match('~^X-Request-Id: ([0-9a-zA-Z]{32})~ism', $header_string, $result); 388 | $this->x_request_id = isset($result[1]) ? $result[1] : ''; 389 | } 390 | } 391 | 392 | 393 | class UpYunException extends Exception 394 | { 395 | public function __construct($message, $code, Exception $previous = null) 396 | { 397 | parent::__construct($message, $code); // For PHP 5.2.x 398 | } 399 | 400 | public function __toString() 401 | { 402 | return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; 403 | } 404 | } 405 | 406 | class UpYunAuthorizationException extends UpYunException 407 | { 408 | public function __construct($message, $code = 0, Exception $previous = null) 409 | { 410 | parent::__construct($message, 401, $previous); 411 | } 412 | } 413 | 414 | class UpYunForbiddenException extends UpYunException 415 | { 416 | public function __construct($message, $code = 0, Exception $previous = null) 417 | { 418 | parent::__construct($message, 403, $previous); 419 | } 420 | } 421 | 422 | class UpYunNotFoundException extends UpYunException 423 | { 424 | public function __construct($message, $code = 0, Exception $previous = null) 425 | { 426 | parent::__construct($message, 404, $previous); 427 | } 428 | } 429 | 430 | class UpYunNotAcceptableException extends UpYunException 431 | { 432 | public function __construct($message, $code = 0, Exception $previous = null) 433 | { 434 | parent::__construct($message, 406, $previous); 435 | } 436 | } 437 | 438 | class UpYunServiceUnavailable extends UpYunException 439 | { 440 | public function __construct($message, $code = 0, Exception $previous = null) 441 | { 442 | parent::__construct($message, 503, $previous); 443 | } 444 | } 445 | --------------------------------------------------------------------------------