TildaAPI.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. <?php
  2. namespace manager\models;
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /**
  5. * Tilda Publishing
  6. *
  7. * @copyright (C) 2015 Оbukhov Nikita Valentinovich. Russia
  8. * @license MIT
  9. *
  10. * @author Nikita Obukhov <hello@tilda.cc>
  11. * @author Michael Akimov <michael@island-future.ru>
  12. *
  13. * Описание:
  14. * Класс для работы с API tilda.cc
  15. */
  16. ///////////////////////////////////////////////////////////////////////////////
  17. //use Yii;
  18. class TildaAPI extends \Yii\base\Component
  19. {
  20. protected $apiUrl = "https://api.tildacdn.info/v1/";
  21. /**
  22. * Curl handler
  23. *
  24. * @var resource
  25. */
  26. protected $ch;
  27. /**
  28. * Query timeout
  29. *
  30. * @var int
  31. */
  32. public $timeout = 20;
  33. /**
  34. * Tilda public key
  35. *
  36. * @var string
  37. */
  38. protected $publicKey;
  39. /**
  40. * Tilda secret key
  41. *
  42. * @var string
  43. */
  44. protected $secretKey;
  45. /**
  46. * Need for store last error
  47. *
  48. * @var string
  49. */
  50. public $lastError = '';
  51. public $local = null;
  52. /**
  53. * инициализируем класс
  54. *
  55. * $arOptions - массив дополнительных параметров
  56. **/
  57. public function __construct($publicKey, $secretKey)
  58. {
  59. $this->publicKey = $publicKey;
  60. $this->secretKey = $secretKey;
  61. $this->ch = curl_init();
  62. curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
  63. curl_setopt($this->ch, CURLOPT_HEADER, 0);
  64. curl_setopt($this->ch, CURLOPT_TIMEOUT, $this->timeout);
  65. curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
  66. curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1);
  67. curl_setopt($this->ch, CURLOPT_USERAGENT, 'Tilda-php');
  68. curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
  69. curl_setopt($this->ch, CURLOPT_POST, 0);
  70. $this->local = new LocalProject(array(
  71. 'projectDir' => '/project/all/tilda/',
  72. 'buglovers' => 'cat@amic.ru',
  73. 'baseDir' => '/.www/www/amic.ru/docs/'
  74. )
  75. );
  76. $this->local ->parent = $this;
  77. }
  78. public function __destruct()
  79. {
  80. curl_close($this->ch);
  81. }
  82. /**
  83. * Функция возвращает список проектов пользователя
  84. *
  85. * @return array - список проектов пользователя
  86. */
  87. public function getProjectsList()
  88. {
  89. return $this->call('getprojectslist', array());
  90. }
  91. /**
  92. * Функция возвращает информацию о проекте для экспорта
  93. *
  94. * @param int $projectid
  95. * @param string $webconfig
  96. * @return array|false
  97. */
  98. public function getProjectInfo($projectid, $webconfig = '')
  99. {
  100. if (!in_array($webconfig, array('htaccess', 'nginx'))) {
  101. $webconfig = '';
  102. }
  103. $params = array('projectid' => $projectid);
  104. if (!empty($webconfig)) {
  105. $params['webconfig'] = $webconfig;
  106. }
  107. return $this->call('getprojectinfo', $params);
  108. }
  109. /**
  110. * Функция возвращает список страниц проекта
  111. *
  112. * @param $projectid
  113. * @return array|false
  114. */
  115. public function getPagesList($projectid)
  116. {
  117. return $this->call('getpageslist', array('projectid' => $projectid));
  118. }
  119. /**
  120. * Функция возвращает информацию о странице (+body html-code)
  121. *
  122. * @param int $pageid
  123. * @return array|false
  124. */
  125. public function getPage($pageid)
  126. {
  127. return $this->call('getpage', array('pageid' => $pageid));
  128. }
  129. /**
  130. * Функция возвращает информацию о странице (+full html-code)
  131. *
  132. * @param int $pageid
  133. * @return array|false
  134. */
  135. public function getPageFull($pageid)
  136. {
  137. return $this->call('getpagefull', array('pageid' => $pageid));
  138. }
  139. /**
  140. * Функция возвращает Информация о странице для экспорта (+body html-code)
  141. *
  142. * @param int $pageid
  143. * @return array|false
  144. */
  145. public function getPageExport($pageid)
  146. {
  147. return $this->call('getpageexport', array('pageid' => $pageid));
  148. }
  149. /**
  150. * Информация о странице для экспорта (+full html-code)
  151. *
  152. * @param int $pageid
  153. * @return array|false
  154. */
  155. public function getPageFullExport($pageid)
  156. {
  157. return $this->call('getpagefullexport', array('pageid' => $pageid));
  158. }
  159. /**
  160. * Метод обращается к API Tilda и возвращает обратно ответ
  161. *
  162. * @param string $method Название метода
  163. * @param array $params Список параметров, которые нужно передать в Tilda API
  164. * @return array|false Массив данных или false в случае ошибки
  165. */
  166. public function call($method, $params)
  167. {
  168. $this->lastError = '';
  169. /* список методов и обязательный параметров */
  170. $arTildaMethods = array(
  171. 'getprojectslist' => array(),
  172. 'getprojectinfo' => array('required' => array('projectid')),
  173. 'getpageslist' => array('required' => array('projectid')),
  174. 'getpage' => array('required' => array('pageid')),
  175. 'getpagefull' => array('required' => array('pageid')),
  176. 'getpageexport' => array('required' => array('pageid')),
  177. 'getpagefullexport' => array('required' => array('pageid')),
  178. );
  179. /* проверяем, может в API такого метода нет */
  180. if (!isset($arTildaMethods[$method])) {
  181. $this->lastError = 'Unknown Method: ' . $method;
  182. return false;
  183. }
  184. /* проверяем, все ли необходимые параметры указали */
  185. if (isset($arTildaMethods[$method]['required'])) {
  186. foreach ($arTildaMethods[$method]['required'] as $param) {
  187. if (!isset($params[$param])) {
  188. $this->lastError = 'Param [' . $param . '] required for method [' . $method . ']';
  189. return false;
  190. }
  191. }
  192. }
  193. $params['publickey'] = $this->publicKey;
  194. $params['secretkey'] = $this->secretKey;
  195. $query = http_build_query($params);
  196. /* отправляем запрос в API */
  197. try {
  198. curl_setopt($this->ch, CURLOPT_URL, $this->apiUrl . $method . '/?' . $query);
  199. $result = curl_exec($this->ch);
  200. $reqErr = curl_errno($this->ch);
  201. $reqHeader = curl_getinfo($this->ch);
  202. } catch (\Exception $e) {
  203. $this->lastError = 'Network error';
  204. return false;
  205. }
  206. /* проверяем, полученный результат, декодируем его из JSON и отдаем пользователю */
  207. if ($result && substr($result, 0, 1) == '{') {
  208. $result = json_decode($result, true);
  209. if (isset($result['status'])) {
  210. if ($result['status'] == 'FOUND') {
  211. return $result['result'];
  212. } elseif (isset($result['message'])) {
  213. $this->lastError = $result['message'];
  214. } else {
  215. $this->lastError = 'Not found data';
  216. }
  217. return false;
  218. } else {
  219. $this->lastError = 'Not found data';
  220. return false;
  221. }
  222. } else {
  223. $this->lastError = 'Unknown Error [' . $result . ']';
  224. return false;
  225. }
  226. }
  227. }
  228. ///////////////////////////////////////////////////////////////////////////////
  229. /**
  230. *
  231. * Описание:
  232. * Функционал для экспорта страниц
  233. * Класс для работы с API tilda.cc
  234. *
  235. **/
  236. ///////////////////////////////////////////////////////////////////////////////
  237. class LocalProject
  238. {
  239. /* Корневая директорая Вашего сайта (абсолютный путь) */
  240. public $baseDir;
  241. /* директория, куда будут сохраняться данные проекта (указываем путь относительно корневой директории) */
  242. public $projectDir;
  243. /**
  244. * Данные по проекту
  245. *
  246. * @var array
  247. */
  248. public $arProject = array();
  249. /**
  250. * Массивы, куда собираются названия файлов в HTML файле страницы
  251. */
  252. public $arSearchFiles=array();
  253. public $arSearchImages=array();
  254. /**
  255. * Массивы, куда собираются новые названия файлов на которые нужно поменять, те что в HTML
  256. */
  257. public $arReplaceFiles=array();
  258. public $arReplaceImages=array();
  259. public $emailFrom = 'postmaster';
  260. public $buglovers = 'you@mail.there';
  261. public $lastError = '';
  262. public $parent = null;
  263. /**
  264. * инициализируем класс
  265. *
  266. * $arOptions - массив дополнительных параметров
  267. **/
  268. public function __construct($arOptions = array())
  269. {
  270. umask(0);
  271. /* базовая директория, относительно которой все и создается */
  272. if (! empty($arOptions['baseDir'])) {
  273. $this->baseDir = $arOptions['baseDir'];
  274. } elseif(empty($_SERVER['DOCUMENT_ROOT'])) {
  275. $this->baseDir = dirname(__DIR__);
  276. } else {
  277. $this->baseDir = $_SERVER['DOCUMENT_ROOT'];
  278. }
  279. if (substr($this->baseDir,-1) != DIRECTORY_SEPARATOR && substr($this->baseDir,-1) != '/') {
  280. $this->baseDir .= DIRECTORY_SEPARATOR;
  281. }
  282. /* у каждого проекта есть свой набор стилей и скриптов - храним их отдельно */
  283. if (! empty($arOptions['projectDir'])) {
  284. $this->projectDir = $arOptions['projectDir'];
  285. if (substr($this->projectDir,0,1) == DIRECTORY_SEPARATOR || substr($this->projectDir,0,1) == '/') {
  286. $this->projectDir = substr($this->projectDir,1);
  287. }
  288. if (! file_exists($this->baseDir . $this->projectDir)) {
  289. if (!mkdir($this->baseDir . $this->projectDir, 0776, true)) {
  290. throw new Exception('Cannot create Project dir [' . $this->baseDir.$this->projectDir . ']'."\n");
  291. }
  292. }
  293. if (substr($this->projectDir,-1) != DIRECTORY_SEPARATOR && substr($this->projectDir,-1) != '/') {
  294. $this->projectDir .= DIRECTORY_SEPARATOR;
  295. }
  296. } else {
  297. $this->projectDir = '';
  298. }
  299. if (isset($arOptions['buglovers'])) {
  300. $this->buglovers = $arOptions['buglovers'];
  301. }
  302. }
  303. public function __destruct()
  304. {
  305. }
  306. /* возвращает относительный путь проекта */
  307. public function getProjectDir()
  308. {
  309. return $this->projectDir;
  310. }
  311. public function setProjectDir($dir)
  312. {
  313. $this->projectDir = $dir;
  314. }
  315. /* возвращает абсолютный путь до директорий проекта */
  316. public function getProjectFullDir()
  317. {
  318. return $this->baseDir . $this->projectDir;
  319. }
  320. public function setProject(&$arProject)
  321. {
  322. $this->arProject = $arProject;
  323. }
  324. public function copyCssFiles($subdir)
  325. {
  326. $this->lastError = '';
  327. if (empty($this->arProject) || empty($this->arProject['css'])) {
  328. $this->lastError = "Not found project or empty css";
  329. return false;
  330. }
  331. $upload_path = '/' . $this->getProjectDir();
  332. if (DIRECTORY_SEPARATOR != '/') {
  333. $upload_path = str_replace(DIRECTORY_SEPARATOR,'/', $upload_path);
  334. }
  335. $letter = substr($subdir,0,1);
  336. if ( $letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  337. $subdir = substr($subdir,1);
  338. }
  339. $letter = substr($subdir,-1);
  340. if ($letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  341. $subdir = substr($subdir,0,-1);
  342. }
  343. $arResult = array();
  344. //css
  345. for ($i=0;$i<count($this->arProject['css']);$i++) {
  346. $newfile = $this->copyFile($this->arProject['css'][$i]['from'], $subdir . DIRECTORY_SEPARATOR . $this->arProject['css'][$i]['to']);
  347. if (! $newfile) {
  348. //die("Error for coping:" . $this->lastError);
  349. return false;
  350. }
  351. $arResult[] = $newfile;
  352. if (substr($this->arProject['css'][$i]['to'],0,4) != 'http' && substr($this->arProject['css'][$i]['to'],0,2) != '//') {
  353. if ($this->arProject['export_csspath'] > '') {
  354. $this->arSearchFiles[] = '|' . $this->arProject['export_csspath'] . '/' . $this->arProject['css'][$i]['to'] . '|i';
  355. } else {
  356. $this->arSearchFiles[] = '|' . $this->arProject['css'][$i]['to'] . '|i';
  357. }
  358. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['css'][$i]['to'];
  359. $this->arSearchFiles[] = '|/' . $upload_path.$subdir.'/'.$this->arProject['css'][$i]['to']. '|i';
  360. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['css'][$i]['to'];
  361. }
  362. }
  363. return $arResult;
  364. }
  365. public function copyJsFiles($subdir)
  366. {
  367. $this->lastError = '';
  368. if (empty($this->arProject) || empty($this->arProject['js'])) {
  369. $this->lastError = "Not found project or empty JS";
  370. return false;
  371. }
  372. $upload_path = '/' . $this->getProjectDir();
  373. if (DIRECTORY_SEPARATOR != '/') {
  374. $upload_path = str_replace(DIRECTORY_SEPARATOR,'/', $upload_path);
  375. }
  376. $letter = substr($subdir,0,1);
  377. if ( $letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  378. $subdir = substr($subdir,1);
  379. }
  380. $letter = substr($subdir,-1);
  381. if ($letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  382. $subdir = substr($subdir,0,-1);
  383. }
  384. $arResult = array();
  385. //js
  386. for ($i=0;$i<count($this->arProject['js']);$i++) {
  387. $newfile = $this->copyFile($this->arProject['js'][$i]['from'], $subdir . DIRECTORY_SEPARATOR . $this->arProject['js'][$i]['to']);
  388. if (! $newfile) {
  389. //die("Error for coping:" . $this->lastError);
  390. return false;
  391. }
  392. $arResult[] = $newfile;
  393. if (substr($this->arProject['js'][$i]['to'],0,4) != 'http' && substr($this->arProject['js'][$i]['to'],0,2) != '//') {
  394. if ($this->arProject['export_jspath'] > '') {
  395. $this->arSearchFiles[] = '|' . $this->arProject['export_jspath'] . '/' . $this->arProject['js'][$i]['to'] . '|i';
  396. } else {
  397. $this->arSearchFiles[] = '|' . $this->arProject['js'][$i]['to'] . '|i';
  398. }
  399. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['js'][$i]['to'];
  400. $this->arSearchFiles[] = '|/' . $upload_path.$subdir.'/'.$this->arProject['js'][$i]['to']. '|i';
  401. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['js'][$i]['to'];
  402. }
  403. }
  404. return $arResult;
  405. }
  406. public function copyImagesFiles($subdir)
  407. {
  408. $this->lastError = '';
  409. if (empty($this->arProject) || empty($this->arProject['images'])) {
  410. $this->lastError = "Not found project or empty Images";
  411. return false;
  412. }
  413. $upload_path = '/' . $this->getProjectDir();
  414. if (DIRECTORY_SEPARATOR != '/') {
  415. $upload_path = str_replace(DIRECTORY_SEPARATOR,'/', $upload_path);
  416. }
  417. $letter = substr($subdir,0,1);
  418. if ( $letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  419. $subdir = substr($subdir,1);
  420. }
  421. $letter = substr($subdir,-1);
  422. if ($letter == '/' || $letter == DIRECTORY_SEPARATOR) {
  423. $subdir = substr($subdir,0,-1);
  424. }
  425. $arResult = array();
  426. //js
  427. for ($i=0;$i<count($this->arProject['images']);$i++) {
  428. $newfile = $this->copyFile($this->arProject['images'][$i]['from'], $subdir . DIRECTORY_SEPARATOR . $this->arProject['images'][$i]['to']);
  429. if (! $newfile) {
  430. //die("Error for coping:" . $this->lastError);
  431. return false;
  432. }
  433. $arResult[] = $newfile;
  434. if (substr($this->arProject['images'][$i]['to'],0,4) != 'http' && substr($this->arProject['images'][$i]['to'],0,2) != '//') {
  435. if ($this->arProject['export_imgpath'] > '') {
  436. $this->arSearchFiles[] = '|' . $this->arProject['export_imgpath'] . '/' . $this->arProject['images'][$i]['to'] . '|i';
  437. } else {
  438. /*
  439. if ($this->arProject['images'][$i]['to'] == 'tildafavicon.ico') {
  440. $this->arSearchFiles[] = '|//tilda.ws/img/' . $this->arProject['images'][$i]['to'] . '|i';
  441. $this->arReplaceFiles[] = $this->arProject['images'][$i]['to'];
  442. }
  443. */
  444. $this->arSearchFiles[] = '|' . $this->arProject['images'][$i]['to'] . '|i';
  445. }
  446. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['images'][$i]['to'];
  447. } else {
  448. $this->arSearchFiles[] = '|' . $this->arProject['images'][$i]['to'] . '|i';
  449. $this->arReplaceFiles[] = $upload_path.$subdir.'/'.$this->arProject['images'][$i]['to'];
  450. }
  451. }
  452. return $arResult;
  453. }
  454. /**
  455. * создаем базовые папки, для хранения css, js, img
  456. * @return boolean в случае ошибки возвращается FALSE и текст ошибки помещается в Tilda::$lastError
  457. **/
  458. public function createBaseFolders()
  459. {
  460. $flag=true;
  461. $this->lastError = '';
  462. $basedir = $this->baseDir;
  463. $fullprojectdir = $this->getProjectFullDir();
  464. /*
  465. if ($basedir <> "") {
  466. if (!file_exists($basedir)) {
  467. if (mkdir($basedir, 0776, true)){
  468. echo "Folder created: ".$basedir . "\n";
  469. } else {
  470. $this->lastError .= "Failed folder creation: ".$basedir."\n";
  471. $flag=false;
  472. }
  473. }
  474. if (!is_writable($basedir)) {
  475. $this->lastError .= "Folder must be writable: ".$basedir." Please change folder attribute to 0776\n";
  476. $flag=false;
  477. }
  478. }
  479. */
  480. if ($fullprojectdir <> "") {
  481. if (!file_exists($fullprojectdir)) {
  482. if (mkdir($fullprojectdir, 0776, true)) {
  483. // echo"Folder created: ".$fullprojectdir."\n";
  484. // chgrp($fullprojectdir, 'admin');
  485. } else {
  486. $this->lastError .= "Failed folder creation: ".$fullprojectdir."\n";
  487. $flag=false;
  488. }
  489. }
  490. }
  491. if (! file_exists($fullprojectdir.'css')) {
  492. if (mkdir($fullprojectdir.'css', 0776, true)){
  493. // echo "Folder created: ".$fullprojectdir.'css'."\n";
  494. } else {
  495. $this->lastError .= "Failed folder creation: ".$fullprojectdir.'css'."\n";
  496. $flag = false;
  497. }
  498. }
  499. if (!file_exists($fullprojectdir.'js')) {
  500. if (mkdir($fullprojectdir.'js', 0776, true)){
  501. // echo "Folder created: ".$fullprojectdir.'js'."\n";
  502. }else{
  503. $this->lastError .= "Failed folder creation: ".$fullprojectdir.'js'."\n";
  504. $flag=false;
  505. }
  506. }
  507. if (!file_exists($fullprojectdir.'img')) {
  508. if (mkdir($fullprojectdir.'img', 0776, true)) {
  509. // echo "Folder created: ".$fullprojectdir.'img'."\n";
  510. } else {
  511. $this->lastError .= "Failed folder creation: ".$fullprojectdir.'img'."\n";
  512. $flag=false;
  513. }
  514. }
  515. if (!file_exists($fullprojectdir.'meta')) {
  516. if (mkdir($fullprojectdir.'meta', 0776, true)) {
  517. // echo "Folder created: ".$fullprojectdir.'meta'."\n";
  518. } else {
  519. $this->lastError .= "Failed folder creation: ".$fullprojectdir.'meta'."\n";
  520. $flag=false;
  521. }
  522. }
  523. return($flag);
  524. }
  525. /**
  526. * Копируем файлы извне в указанную директорию относительно директории проекта
  527. */
  528. function copyFile($from,$to)
  529. {
  530. $this->lastError = '';
  531. if ($from == '') {
  532. $this->lastError="Error. Source file url is empty!\n";
  533. return false;
  534. }
  535. if ($to == '') {
  536. $this->lastError = "Error. File name is empty!\n";
  537. return false;
  538. }
  539. $fullprojectdir = $this->baseDir.$this->projectDir;
  540. $newfile=$fullprojectdir.$to;
  541. // $from = preg_replace( '/^\/\//', 'https://', $from);
  542. if (!strstr($from,"://")) $from="https:".$from;
  543. if (copy($from, $newfile)) {
  544. if(substr(sprintf('%o', fileperms($newfile)), -4) !== "0666"){
  545. if(!chmod($newfile, 0666)){
  546. $this->lastError = '. But can\'t set permission for file to 0776 because '.sprintf('%o', fileperms($newfile));
  547. return false;
  548. }
  549. }
  550. return $newfile;
  551. } else {
  552. $this->lastError = "(a) Copy failed: ".$newfile;
  553. return false;
  554. }
  555. }
  556. /**
  557. * Копируем файлы, если они не существуют, если существуют, то пропускаем
  558. *
  559. * @param string $from - URL картинки
  560. * @param string $dir - каталог относительно каталога проекта, куда будет помещен файл
  561. * @param boolean $isRewrite - если установлен в true, то картинка перезаписывается, иначе нет
  562. *
  563. * @return string имя файла под которым сохранено на диске
  564. */
  565. public function copyImageTo($from, $dir, $isRewrite=false)
  566. {
  567. if (substr($dir,0,2) == '//') {
  568. $fullprojectdir = $this->getProjectFullDir();
  569. } elseif (substr($dir,0,1) == DIRECTORY_SEPARATOR) {
  570. $fullprojectdir = $dir;
  571. } else {
  572. $fullprojectdir = $this->getProjectFullDir() . $dir;
  573. }
  574. $newfile = md5($from);
  575. if (! file_exists($fullprojectdir)) {
  576. if (! mkdir($fullprojectdir, '0776', true)) {
  577. die("Cannot create directory [" . $fullprojectdir . "]\n");
  578. }
  579. }
  580. $pos = strrpos($from,'.');
  581. if ($pos > 0) {
  582. $ext = strip_tags(addslashes(substr($from,$pos+1)));
  583. } else {
  584. $ext = '';
  585. }
  586. // echo "==> copy file from: $from ".($isRewrite ? 'with rewrite' : 'without rewirite')."\n";
  587. /* если */
  588. if (file_exists($fullprojectdir.$newfile.'.'.$ext) && $isRewrite==false) {
  589. echo 'File already exist: ' . $newfile . ".$ext<br>\n";
  590. } else {
  591. /* закачиваем файл */
  592. copy($from, $fullprojectdir . $newfile);
  593. /*
  594. if (class_exists('finfo', false)) {
  595. $finfo = new \finfo(FILEINFO_MIME_TYPE);
  596. $mime = $finfo->file($fullprojectdir . $newfile);
  597. if (strpos($mime,'html')!== false || strpos($mime,'text')!== false || strpos($mime,'xml')!== false ) {
  598. $file = file_get_contents($fullprojectdir . $newfile);
  599. $pos = strpos($file,'<svg');
  600. if ($pos!==false) {
  601. $mime = 'image/svg+xml';
  602. } else {
  603. $pos = strpos($file,'<SVG');
  604. if ($pos!==false) {
  605. $mime = 'image/svg+xml';
  606. }
  607. }
  608. }
  609. } else {
  610. */
  611. $size = @getimagesize($fullprojectdir . $newfile);
  612. $mime = '';
  613. if (is_array($size) && !empty($size['mime'])) {
  614. $mime = $size['mime'];
  615. }
  616. if ($mime == ''){
  617. $file = file_get_contents($fullprojectdir . $newfile);
  618. $pos = strpos($file,'<svg');
  619. if ($pos!==false) {
  620. $mime = 'image/svg+xml';
  621. } else {
  622. $pos = strpos($file,'<SVG');
  623. if ($pos!==false) {
  624. $mime = 'image/svg+xml';
  625. }
  626. }
  627. }
  628. //}
  629. /* определяем тип изображения */
  630. if(empty($mime)) {
  631. $ext = '';
  632. } else {
  633. $img = null;
  634. if ($mime == 'image/jpeg') {
  635. $ext = 'jpg';
  636. } elseif ($mime == 'image/png') {
  637. $ext = 'png';
  638. } elseif ($mime == 'image/gif') {
  639. $ext = 'gif';
  640. } elseif ($mime == 'image/svg' || $mime == 'image/svg+xml') {
  641. $ext = 'svg';
  642. } else {
  643. echo "Unkonwn image type $mime for file $from<br>\n";
  644. }
  645. }
  646. // echo('File copied: '. $fullprojectdir . $newfile.".$ext\n");
  647. /* переименовываем файл, добавляя ему расширение */
  648. rename($fullprojectdir . $newfile, $fullprojectdir . $newfile . '.' . $ext);
  649. if(substr(sprintf('%o', fileperms($fullprojectdir . $newfile . '.' . $ext)), -4) !== "0666"){
  650. if(!chmod($fullprojectdir . $newfile . '.' . $ext, 0666)){
  651. echo('. But can\'t set permission for file to 0666'.sprintf('%o', fileperms($fullprojectdir . $newfile . '.' . $ext))."<br>\n");
  652. die();
  653. }
  654. }
  655. }
  656. /* возвращаем новое название файла */
  657. return $newfile . '.' . $ext;
  658. }
  659. function createPage($to,$str)
  660. {
  661. $fullprojectdir=$this->baseDir.$this->projectDir;
  662. $newfile=$fullprojectdir.$to;
  663. if (file_put_contents($newfile, $str)) {
  664. // echo('<li>File created: '.$newfile);
  665. if (!chmod($newfile, 0776)) {
  666. echo('. But can\'t set permission for file to 0776');
  667. }
  668. } else {
  669. echo "file create failed: ".$newfile."<br>\n";
  670. }
  671. }
  672. /* показываем страницу, если она есть */
  673. public function showPage($name)
  674. {
  675. $this->lastError = '';
  676. if (file_exists($this->getProjectFullDir().'meta'.DIRECTORY_SEPARATOR.$name.'.php')) {
  677. $arPage = include $this->getProjectFullDir().'meta'.DIRECTORY_SEPARATOR.$name.'.php';
  678. } elseif (file_exists($this->getProjectFullDir().'meta'.DIRECTORY_SEPARATOR.'page'.intval($name).'.php')) {
  679. $arPage = include $this->getProjectFullDir().'meta'.DIRECTORY_SEPARATOR.'page'.intval($name).'.php';
  680. } else {
  681. $this->lastError = 'Page config file not found';
  682. return false;
  683. }
  684. if (! empty($arPage['id']) && file_exists($this->getProjectFullDir() . $arPage['id'] . '.html')) {
  685. include $this->getProjectFullDir() . $arPage['id'] . '.html';
  686. } else {
  687. $this->lastError = 'Html file not found';
  688. return false;
  689. }
  690. return true;
  691. }
  692. /* заменяем все картинки в HTML-страницы, на локальные адреса */
  693. public function replaceOuterImageToLocal($tildapage, $export_imgpath='', $upload_path='')
  694. {
  695. $exportimages = array();
  696. $replaceimages = array();
  697. if ($upload_path == '') {
  698. $upload_dir = $this->getProjectFullDir() . 'img'. DIRECTORY_SEPARATOR;
  699. $upload_path = '/' . $this->getProjectDir() . 'img/';
  700. if (DIRECTORY_SEPARATOR != '/') {
  701. $upload_path = str_replace(DIRECTORY_SEPARATOR,'/', $upload_path);
  702. }
  703. if (!file_exists($upload_dir)) {
  704. mkdir($upload_dir, '0776', true);
  705. }
  706. }
  707. $uniq = array();
  708. $html = null;
  709. if (! empty($tildapage['images']) && sizeof($tildapage['images']) > 0) {
  710. foreach ($tildapage['images'] as $image) {
  711. if( isset($uniq[$image['from']]) ){ continue; }
  712. $uniq[$image['from']] = 1;
  713. if ($export_imgpath > '') {
  714. $exportimages[] = '|'.$export_imgpath.'/'.$image['to'].'|i';
  715. } else {
  716. $exportimages[] = '|'.$image['to'].'|i';
  717. }
  718. if (!empty($image['local'])) {
  719. $to = $image['local'];
  720. } else {
  721. $to = $image['to'];
  722. }
  723. if(substr($to,0,1) == '/' && substr($upload_path,-1)=='/') {
  724. $replaceimages[] = $upload_path.substr($to,1);
  725. } else {
  726. $replaceimages[] = $upload_path.$to;
  727. }
  728. }
  729. // print_a( $exportimages );
  730. // print_a( $replaceimages );
  731. $html = preg_replace($exportimages, $replaceimages, $tildapage['html']);
  732. } else {
  733. $html = $tildapage['html'];
  734. }
  735. if ($html) {
  736. $tildapage['html'] = $html;
  737. }
  738. return $tildapage;
  739. }
  740. /**
  741. * Сохраняем страницу
  742. */
  743. public function savePage($tildapage)
  744. {
  745. $filename = 'page' . $tildapage['id'] . '.html';
  746. $upload_path = $this->getProjectFullDir();
  747. if (! file_exists($upload_path)) {
  748. mkdir($upload_path,'0776', true);
  749. }
  750. for ($ii = 0; $ii < count($tildapage['images']); $ii++) {
  751. // echo "Copy image [".$tildapage['images'][$ii]['from']."] \n";
  752. $tildapage['images'][$ii]['local'] = $this->copyImageTo($tildapage['images'][$ii]['from'], 'img' . DIRECTORY_SEPARATOR, true);
  753. }
  754. if ($tildapage['img'] && (substr($tildapage['img'],0,4) == 'http' || substr($tildapage['img'],0,2) == '//')) {
  755. $tmp = $this->copyImageTo($tildapage['img'], 'img' . DIRECTORY_SEPARATOR, true);
  756. $tildapage['images'][] = array(
  757. 'from' => $tildapage['img'],
  758. 'to' => $tildapage['img'],
  759. 'local' => $tmp
  760. );
  761. $tildapage['img'] = $tmp;
  762. }
  763. if ( isset($tildapage['featureimg']) && $tildapage['featureimg'] && (substr($tildapage['featureimg'],0,4) == 'http' || substr($tildapage['featureimg'],0,2) == '//')) {
  764. $tmp = $this->copyImageTo($tildapage['featureimg'], 'img' . DIRECTORY_SEPARATOR, true);
  765. $tildapage['images'][] = array(
  766. 'from' => $tildapage['featureimg'],
  767. 'to' => $tildapage['featureimg'],
  768. 'local' => $tmp
  769. );
  770. $tildapage['featureimg'] = $tmp;
  771. }
  772. if ( isset($tildapage['fb_img']) && $tildapage['fb_img'] && (substr($tildapage['fb_img'],0,4) == 'http' || substr($tildapage['fb_img'],0,2) == '//')) {
  773. $tmp = $this->copyImageTo($tildapage['fb_img'], 'img' . DIRECTORY_SEPARATOR, true);
  774. $tildapage['images'][] = array(
  775. 'from' => $tildapage['fb_img'],
  776. 'to' => $tildapage['fb_img'],
  777. 'local' => $tmp
  778. );
  779. $tildapage['fb_img'] = $tmp;
  780. }
  781. /* заменяем пути до картинок в HTML на новые (куда картинки скачались) */
  782. //echo $tildapage['export_imgpath']."<br>";
  783. $tildapage = $this->replaceOuterImageToLocal($tildapage, '/img', '');
  784. /* сохраняем HTML */
  785. file_put_contents($this->getProjectFullDir() . $filename, $tildapage['html']);
  786. return $tildapage;
  787. }
  788. /* сохраняем мета данные о странице (нужно ли обновлять, заголовок, обложку и т.п.) */
  789. public function saveMetaPage($page)
  790. {
  791. if (empty($page['needsync'])) {
  792. $page['needsync'] = '0';
  793. }
  794. if(empty($page['socnetimg'])) { $page['socnetimg'] = '';}
  795. $phpcontent = <<<EOT
  796. <?php
  797. return array(
  798. 'id' => '{$page['id']}',
  799. 'title' => '{$page['title']}',
  800. 'alias' => '{$page['alias']}',
  801. 'descr' => '{$page['descr']}',
  802. 'img' => '{$page['img']}',
  803. 'featureimg' => '{$page['featureimg']}',
  804. 'socnetimg' => '{$page['socnetimg']}',
  805. 'needsync' => '{$page['needsync']}'
  806. );
  807. ?>
  808. EOT;
  809. $metaname = 'page'.$page['id'] . '.php';
  810. file_put_contents($this->getProjectFullDir().'meta' . DIRECTORY_SEPARATOR . $metaname, $phpcontent);
  811. if ($page['alias'] > '') {
  812. file_put_contents($this->getProjectFullDir().'meta' . DIRECTORY_SEPARATOR . $page['alias'] . '.php', '<?php return include "'.$metaname.'"; ?>');
  813. }
  814. $data = array();
  815. $data['dir'] = $this->getProjectDir();
  816. // $d = $this->parent->getPage($page['id']);
  817. // <!--/allrecords-->
  818. // <!--allrecords-->
  819. if( preg_match( '/\<\!--allrecords--\>(.*)\<\!--\/allrecords--\>/s', $page['html'], $a ) ){
  820. $data['html'] = $a[1];
  821. $data['html'] = str_replace('"img/', '"/'.$data['dir'].'img/',$data['html']);
  822. for ($i=0;$i<count($this->arProject['css']);$i++) {
  823. $data['css'][] = $this->arProject['css'][$i]['to'];
  824. }
  825. for ($i=0;$i<count($this->arProject['css']);$i++) {
  826. $data['js'][] = $this->arProject['js'][$i]['to'];
  827. }
  828. $phpcontent = json_encode($data);
  829. $metaname = 'inc'.$page['id'] . '.json';
  830. file_put_contents($this->getProjectFullDir().'meta' . DIRECTORY_SEPARATOR . $metaname, $phpcontent);
  831. }
  832. return $page;
  833. }
  834. /* в случае ошибки отправляет сообщение, выводит JSON сообщение об ошибке и завершает работу скрипта */
  835. public function errorEnd($message)
  836. {
  837. if ($this->buglovers > '') {
  838. $headers = 'From: ' . $this->emailFrom;
  839. $emailto = $this->buglovers;
  840. @mail($emailto, 'Tilda Sync Error', $message, $headers);
  841. }
  842. die('{"error":"'.htmlentities($message).'"}');
  843. }
  844. /* в случае успеха, выводит JSON сообщение и завершает работу скрипта */
  845. public function successEnd($message='OK')
  846. {
  847. if ($this->buglovers > '') {
  848. $headers = 'From: ' . $this->emailFrom;
  849. $emailto = $this->buglovers;
  850. @mail($emailto, 'Tilda Sync OK', $message, $headers);
  851. }
  852. die('{"result":"OK"}');
  853. }
  854. }