Ueditor.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace app\shop\controller;
  11. use app\Controller;
  12. use app\model\upload\Upload as UploadModel;
  13. /**
  14. * 百度编辑器上传
  15. * 版本 1.0.6
  16. */
  17. class Ueditor extends Controller
  18. {
  19. public function index()
  20. {
  21. date_default_timezone_set("Asia/chongqing");
  22. error_reporting(E_ERROR);
  23. header("Content-Type: text/html; charset=utf-8");
  24. $CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("./public/static/ext/ueditor/php/config.json")), true);
  25. $action = $_GET[ 'action' ];
  26. switch ( $action ) {
  27. case 'config':
  28. $result = json_encode($CONFIG);
  29. break;
  30. /* 上传图片 */
  31. case 'uploadimage':
  32. $fieldName = $CONFIG[ 'imageFieldName' ];
  33. $result = $this->upImage($fieldName);
  34. break;
  35. /* 上传涂鸦 */
  36. case 'uploadscrawl':
  37. $config = array (
  38. "pathFormat" => $CONFIG[ 'scrawlPathFormat' ],
  39. "maxSize" => $CONFIG[ 'scrawlMaxSize' ],
  40. "allowFiles" => $CONFIG[ 'scrawlAllowFiles' ],
  41. "oriName" => "scrawl.png"
  42. );
  43. $fieldName = $CONFIG[ 'scrawlFieldName' ];
  44. $base64 = "base64";
  45. $result = $this->upBase64($config, $fieldName);
  46. break;
  47. /* 上传视频 */
  48. case 'uploadvideo':
  49. $fieldName = $CONFIG[ 'videoFieldName' ];
  50. $result = $this->upVideo($fieldName, $CONFIG[ 'videoMaxSize' ]);
  51. break;
  52. /* 上传文件 */
  53. case 'uploadfile':
  54. $fieldName = $CONFIG[ 'fileFieldName' ];
  55. $result = $this->upFile($fieldName);
  56. break;
  57. /* 列出图片 */
  58. case 'listimage':
  59. $allowFiles = $CONFIG[ 'imageManagerAllowFiles' ];
  60. $listSize = $CONFIG[ 'imageManagerListSize' ];
  61. $path = $CONFIG[ 'imageManagerListPath' ];
  62. $get = $_GET;
  63. $result = $this->fileList($allowFiles, $listSize, $get);
  64. break;
  65. /* 列出文件 */
  66. case 'listfile':
  67. $allowFiles = $CONFIG[ 'fileManagerAllowFiles' ];
  68. $listSize = $CONFIG[ 'fileManagerListSize' ];
  69. $path = $CONFIG[ 'fileManagerListPath' ];
  70. $get = $_GET;
  71. $result = $this->fileList($allowFiles, $listSize, $get);
  72. break;
  73. /* 抓取远程文件 */
  74. case 'catchimage':
  75. $config = array (
  76. "pathFormat" => $CONFIG[ 'catcherPathFormat' ],
  77. "maxSize" => $CONFIG[ 'catcherMaxSize' ],
  78. "allowFiles" => $CONFIG[ 'catcherAllowFiles' ],
  79. "oriName" => "remote.png"
  80. );
  81. $fieldName = $CONFIG[ 'catcherFieldName' ];
  82. /* 抓取远程图片 */
  83. $list = array ();
  84. isset($_POST[ $fieldName ]) ? $source = $_POST[ $fieldName ] : $source = $_GET[ $fieldName ];
  85. foreach ($source as $imgUrl) {
  86. $info = json_decode($this->saveRemote($config, $imgUrl), true);
  87. array_push($list, array (
  88. "state" => $info[ "state" ],
  89. "url" => $info[ "url" ],
  90. "size" => $info[ "size" ],
  91. "title" => htmlspecialchars($info[ "title" ]),
  92. "original" => htmlspecialchars($info[ "original" ]),
  93. "source" => htmlspecialchars($imgUrl)
  94. ));
  95. }
  96. $result = json_encode(array (
  97. 'state' => count($list) ? 'SUCCESS' : 'ERROR',
  98. 'list' => $list
  99. ));
  100. break;
  101. default:
  102. $result = json_encode(array (
  103. 'state' => '请求地址出错'
  104. ));
  105. break;
  106. }
  107. /* 输出结果 */
  108. if (isset($_GET[ "callback" ])) {
  109. if (preg_match("/^[\w_]+$/", $_GET[ "callback" ])) {
  110. echo htmlspecialchars($_GET[ "callback" ]) . '(' . $result . ')';
  111. } else {
  112. echo json_encode(array (
  113. 'state' => 'callback参数不合法'
  114. ));
  115. }
  116. } else {
  117. echo $result;
  118. }
  119. }
  120. /**
  121. * 上传文件
  122. * @param unknown $fieldName
  123. */
  124. private function upFile($fieldName)
  125. {
  126. $upload_service = new Upload();
  127. $upload_path = 'ueditor/file/' . date('Ymd');
  128. if (!empty($_FILES[ $fieldName ])) {//上传成功
  129. $info = $upload_service->file($_FILES[ $fieldName ], $upload_path);
  130. if ($info[ 'code' ] > 0) {
  131. $data = array (
  132. 'state' => 'SUCCESS',
  133. 'url' => $info[ 'data' ][ 'path' ],
  134. 'title' => $info[ 'data' ][ 'file_name' ],
  135. 'original' => $info[ 'data' ][ 'file_name' ],
  136. 'type' => '.' . $info[ 'data' ][ 'file_ext' ],
  137. 'size' => $info[ 'data' ][ 'size' ]
  138. );
  139. } else {
  140. $data = array (
  141. 'state' => $info[ 'message' ]
  142. );
  143. }
  144. } else {
  145. $data = array (
  146. 'state' => '上传文件为空',
  147. );
  148. }
  149. return json_encode($data);
  150. }
  151. /**
  152. * 上传图片
  153. * @param unknown $fieldName
  154. * @return string
  155. */
  156. private function upImage($fieldName)
  157. {
  158. $upload_service = new UploadModel();
  159. $upload_path = 'ueditor/image/' . date('Ymd');
  160. if (!empty($_FILES[ $fieldName ])) {//上传成功
  161. $info = $upload_service->setPath("common/images/" . date("Ymd") . '/')->image([
  162. 'name' => $fieldName,
  163. 'thumb_type' => '',
  164. 'cloud' => 1
  165. ]);
  166. if ($info[ 'code' ] >= 0) {
  167. $data = array (
  168. 'state' => 'SUCCESS',
  169. 'url' => $info[ 'data' ][ 'pic_path' ],
  170. 'title' => $info[ 'data' ][ 'pic_name' ],
  171. 'original' => $info[ 'data' ][ 'pic_name' ],
  172. 'type' => '.' . $info[ 'data' ][ 'file_ext' ],
  173. );
  174. } else {
  175. $data = array (
  176. 'state' => $info[ 'message' ]
  177. );
  178. }
  179. } else {
  180. $data = array (
  181. 'state' => '上传文件为空',
  182. );
  183. }
  184. return json_encode($data);
  185. }
  186. public function upVideo($fieldName, $size)
  187. {
  188. $upload_service = new UploadModel();
  189. if (!empty($_FILES[ $fieldName ])) {//上传成功
  190. $info = $upload_service->setPath("common/video/" . date("Ymd") . '/')->video([
  191. 'name' => $fieldName,
  192. ]);
  193. if ($info[ 'code' ] >= 0) {
  194. $data = array (
  195. 'state' => 'SUCCESS',
  196. 'url' => $info[ 'data' ][ 'path' ],
  197. 'title' => $info[ 'data' ][ 'path' ],
  198. 'original' => $info[ 'data' ][ 'path' ]
  199. );
  200. } else {
  201. $data = array (
  202. 'state' => 'FAIL'
  203. );
  204. }
  205. } else {
  206. $data = array (
  207. 'state' => '上传文件为空',
  208. );
  209. }
  210. return json_encode($data);
  211. }
  212. //列出图片
  213. private function fileList($allowFiles, $listSize, $get)
  214. {
  215. $dirname = __UPLOAD__ . '/ueditor/';
  216. $allowFiles = substr(str_replace(".", "|", join("", $allowFiles)), 1);
  217. /* 获取参数 */
  218. $size = isset($get[ 'size' ]) ? htmlspecialchars($get[ 'size' ]) : $listSize;
  219. $start = isset($get[ 'start' ]) ? htmlspecialchars($get[ 'start' ]) : 0;
  220. $end = $start + $size;
  221. /* 获取文件列表 */
  222. $path = $dirname;
  223. $files = $this->getFiles($path, $allowFiles);
  224. if (!count($files)) {
  225. return json_encode(array (
  226. "state" => "no match file",
  227. "list" => array (),
  228. "start" => $start,
  229. "total" => count($files)
  230. ));
  231. }
  232. /* 获取指定范围的列表 */
  233. $len = count($files);
  234. for ($i = min($end, $len) - 1, $list = array (); $i < $len && $i >= 0 && $i >= $start; $i--) {
  235. $list[] = $files[ $i ];
  236. }
  237. /* 返回数据 */
  238. $result = json_encode(array (
  239. "state" => "SUCCESS",
  240. "list" => $list,
  241. "start" => $start,
  242. "total" => count($files)
  243. ));
  244. return $result;
  245. }
  246. /*
  247. * 遍历获取目录下的指定类型的文件
  248. * @param $path
  249. * @param array $files
  250. * @return array
  251. */
  252. private function getFiles($path, $allowFiles, &$files = array ())
  253. {
  254. if (!is_dir($path)) return null;
  255. if (substr($path, strlen($path) - 1) != '/') $path .= '/';
  256. $handle = opendir($path);
  257. while (false !== ( $file = readdir($handle) )) {
  258. if ($file != '.' && $file != '..') {
  259. $path2 = $path . $file;
  260. if (is_dir($path2)) {
  261. $this->getFiles($path2, $allowFiles, $files);
  262. } else {
  263. if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
  264. $files[] = array (
  265. 'url' => $path2, //substr($path2,1),
  266. 'mtime' => filemtime($path2)
  267. );
  268. }
  269. }
  270. }
  271. }
  272. return $files;
  273. }
  274. private function saveRemote($config, $fieldName)
  275. {
  276. $imgUrl = htmlspecialchars($fieldName);
  277. $imgUrl = str_replace("&amp;", "&", $imgUrl);
  278. //http开头验证
  279. if (strpos($imgUrl, "http") !== 0) {
  280. $data = array (
  281. 'state' => '链接不是http链接',
  282. );
  283. return json_encode($data);
  284. }
  285. //获取请求头并检测死链
  286. $heads = get_headers($imgUrl);
  287. if (!( stristr($heads[ 0 ], "200") && stristr($heads[ 0 ], "OK") )) {
  288. $data = array (
  289. 'state' => '链接不可用',
  290. );
  291. return json_encode($data);
  292. }
  293. //格式验证(扩展名验证和Content-Type验证)
  294. $fileType = strtolower(strrchr($imgUrl, '.'));
  295. if (!in_array($fileType, $config[ 'allowFiles' ]) || stristr($heads[ 'Content-Type' ], "image")) {
  296. $data = array (
  297. 'state' => '链接contentType不正确',
  298. );
  299. return json_encode($data);
  300. }
  301. $upload_service = new UploadModel();
  302. $res = $upload_service->setPath("common/images/" . date("Ymd") . '/')->remotePull($imgUrl);
  303. if ($res[ 'code' ] != 0) {
  304. return json_encode([ 'state' => $res[ 'message' ] ]);
  305. }
  306. preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $m);
  307. return json_encode([
  308. 'state' => 'SUCCESS',
  309. 'url' => img($res[ 'data' ][ 'pic_path' ]),
  310. 'title' => $res[ 'data' ][ 'pic_path' ],
  311. 'original' => $m ? $m[ 1 ] : "",
  312. 'type' => strtolower(strrchr($config[ 'oriName' ], '.')),
  313. 'size' => 0,
  314. ]);
  315. }
  316. //抓取远程图片
  317. private function saveRemoteBackup($config, $fieldName)
  318. {
  319. $imgUrl = htmlspecialchars($fieldName);
  320. $imgUrl = str_replace("&amp;", "&", $imgUrl);
  321. //http开头验证
  322. if (strpos($imgUrl, "http") !== 0) {
  323. $data = array (
  324. 'state' => '链接不是http链接',
  325. );
  326. return json_encode($data);
  327. }
  328. //获取请求头并检测死链
  329. $heads = get_headers($imgUrl);
  330. if (!( stristr($heads[ 0 ], "200") && stristr($heads[ 0 ], "OK") )) {
  331. $data = array (
  332. 'state' => '链接不可用',
  333. );
  334. return json_encode($data);
  335. }
  336. //格式验证(扩展名验证和Content-Type验证)
  337. $fileType = strtolower(strrchr($imgUrl, '.'));
  338. if (!in_array($fileType, $config[ 'allowFiles' ]) || stristr($heads[ 'Content-Type' ], "image")) {
  339. $data = array (
  340. 'state' => '链接contentType不正确',
  341. );
  342. return json_encode($data);
  343. }
  344. //打开输出缓冲区并获取远程图片
  345. ob_start();
  346. $context = stream_context_create(
  347. array ( 'http' => array (
  348. 'follow_location' => false // don't follow redirects
  349. ) )
  350. );
  351. readfile($imgUrl, false, $context);
  352. $img = ob_get_contents();
  353. ob_end_clean();
  354. preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $m);
  355. $dirname = __UPLOAD__ . '/ueditor/image/' . date('Ymd');
  356. $file[ 'oriName' ] = $m ? $m[ 1 ] : "";
  357. $file[ 'filesize' ] = strlen($img);
  358. $file[ 'ext' ] = strtolower(strrchr($config[ 'oriName' ], '.'));
  359. $file[ 'name' ] = uniqid() . $file[ 'ext' ];
  360. $file[ 'fullName' ] = $dirname . '/' . $file[ 'name' ];
  361. $fullName = $file[ 'fullName' ];
  362. //检查文件大小是否超出限制
  363. if ($file[ 'filesize' ] >= ( $config[ "maxSize" ] )) {
  364. $data = array (
  365. 'state' => '文件大小超出网站限制',
  366. );
  367. return json_encode($data);
  368. }
  369. //创建目录失败
  370. if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
  371. $data = array (
  372. 'state' => '目录创建失败',
  373. );
  374. return json_encode($data);
  375. } else if (!is_writeable($dirname)) {
  376. $data = array (
  377. 'state' => '目录没有写权限',
  378. );
  379. return json_encode($data);
  380. }
  381. //移动文件
  382. if (!( file_put_contents($fullName, $img) && file_exists($fullName) )) { //移动失败
  383. $data = array (
  384. 'state' => '写入文件内容错误',
  385. );
  386. return json_encode($data);
  387. } else {
  388. //先拉取到本地在上传到云端
  389. $upload_service = new Upload();
  390. $info = $upload_service->fileStore($dirname, $file[ 'name' ]);
  391. if ($info[ 'code' ] > 0) {
  392. $file[ 'fullName' ] = $info[ 'path' ];
  393. } else {
  394. $data = array (
  395. 'state' => $info[ 'message' ],
  396. );
  397. return json_encode($data);
  398. }
  399. $data = array (
  400. 'state' => 'SUCCESS',
  401. 'url' => $file[ 'fullName' ],
  402. 'title' => $file[ 'name' ],
  403. 'original' => $file[ 'oriName' ],
  404. 'type' => $file[ 'ext' ],
  405. 'size' => $file[ 'filesize' ],
  406. );
  407. }
  408. return json_encode($data);
  409. }
  410. /*
  411. * 处理base64编码的图片上传
  412. * 例如:涂鸦图片上传
  413. */
  414. private function upBase64($config, $fieldName)
  415. {
  416. $base64Data = $_POST[ $fieldName ];
  417. $img = base64_decode($base64Data);
  418. $dirname = __UPLOAD__ . '/ueditor/scrawl/' . date('Ymd');
  419. $file[ 'filesize' ] = strlen($img);
  420. $file[ 'oriName' ] = $config[ 'oriName' ];
  421. $file[ 'ext' ] = strtolower(strrchr($config[ 'oriName' ], '.'));
  422. $file[ 'name' ] = uniqid() . $file[ 'ext' ];
  423. $file[ 'fullName' ] = $dirname . '/' . $file[ 'name' ];
  424. $fullName = $file[ 'fullName' ];
  425. //检查文件大小是否超出限制
  426. if ($file[ 'filesize' ] >= ( $config[ "maxSize" ] )) {
  427. $data = array (
  428. 'state' => '文件大小超出网站限制',
  429. );
  430. return json_encode($data);
  431. }
  432. //创建目录失败
  433. if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) {
  434. $data = array (
  435. 'state' => '目录创建失败',
  436. );
  437. return json_encode($data);
  438. } else if (!is_writeable($dirname)) {
  439. $data = array (
  440. 'state' => '目录没有写权限',
  441. );
  442. return json_encode($data);
  443. }
  444. //移动文件
  445. if (!( file_put_contents($fullName, $img) && file_exists($fullName) )) { //移动失败
  446. $data = array (
  447. 'state' => '写入文件内容错误',
  448. );
  449. } else {
  450. //先拉取到本地在上传到云端
  451. $upload_service = new Upload();
  452. $info = $upload_service->fileStore($dirname, $file[ 'name' ]);
  453. if ($info[ 'code' ] > 0) {
  454. $file[ 'fullName' ] = $info[ 'path' ];
  455. } else {
  456. $data = array (
  457. 'state' => $info[ 'message' ],
  458. );
  459. return json_encode($data);
  460. }
  461. $data = array (
  462. 'state' => 'SUCCESS',
  463. 'url' => substr($file[ 'fullName' ], 1),
  464. 'title' => $file[ 'name' ],
  465. 'original' => $file[ 'oriName' ],
  466. 'type' => $file[ 'ext' ],
  467. 'size' => $file[ 'filesize' ],
  468. );
  469. }
  470. return json_encode($data);
  471. }
  472. }