PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/bors.php

https://bitbucket.org/Balancer/bors-core
PHP | 543 lines | 370 code | 102 blank | 71 comment | 75 complexity | 3cd35c46f40f691ef3aeccccc0868f83 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. #require_once('bors/vhosts_loader.php');
  3. require_once('bors/names.php');
  4. require_once('bors/messages.php');
  5. require_once('bors/objects_array.php');
  6. require_once('bors/object_loader.php');
  7. require_once __DIR__.'/../inc/bors/cross.php';
  8. require_once __DIR__.'/../engines/smarty/global.php';
  9. /**
  10. * @param string|bors_object $class_name
  11. * @param string|integer $object_id
  12. * @param array $args
  13. * @return mixed|null
  14. */
  15. function object_load($class_name, $object_id=NULL, $args=array())
  16. {
  17. if(is_object($class_name))
  18. return $class_name;
  19. // echo "object_load($class_name, $object_id, ".print_r($args, true).")\n";
  20. if(is_numeric($class_name))
  21. $class_name = class_id_to_name($class_name);
  22. if(config('debug.trace_object_load'))
  23. bors_debug::syslog('objects_load', "$class_name(".print_r($object_id, true).")", config('debug_trace_object_load_trace'));
  24. if(!$class_name)
  25. return NULL;
  26. //TODO: сделать отброс пробельных символов
  27. // if(!is_object($object_id))
  28. // $object_id = trim($object_id, "\n\r ");
  29. if(is_null($object_id) && preg_match('/^([\\\\\w]+)__(\w+)={0,}$/', $class_name, $m))
  30. {
  31. $class_name = $m[1];
  32. $object_id = $m[2];
  33. if(!is_numeric($m[2]))
  34. {
  35. if($object_id[0] == 'x')
  36. $object_id = substr($object_id, 1);
  37. $object_id = base64_decode($object_id);
  38. }
  39. }
  40. if(config('debug_objects_create_counting_details'))
  41. {
  42. debug_count_inc("bors_load($class_name)");
  43. // if(preg_match('!matf.aviaport.ru/companies/\d+/edit!', $class))
  44. // echo bors_debug::trace();
  45. }
  46. if($object = class_load($class_name, $object_id, $args))
  47. return $object;
  48. if($object = bors_objects_loaders_meta::object_load($class_name, $object_id))
  49. return $object;
  50. return NULL;
  51. }
  52. /**
  53. * @param string $class_name
  54. * @param integer|string $id
  55. * @return bors_object
  56. */
  57. function &object_new($class_name, $id = NULL)
  58. {
  59. /** @var bors_object $obj */
  60. $obj = new $class_name($id);
  61. if($id !== NULL)
  62. {
  63. $id = call_user_func(array($class_name, 'id_prepare'), $id);
  64. $obj->set_id($id);
  65. }
  66. $obj->b2_configure();
  67. return $obj;
  68. }
  69. function &object_new_instance($class, $id = NULL, $db_update = true, $need_check_data = false)
  70. {
  71. if(is_array($id))
  72. {
  73. $data = $id;
  74. $id = empty($data['id']) ? NULL : $data['id'];
  75. }
  76. else
  77. $data = false;
  78. if(!class_exists($class))
  79. bors_throw("Class name '$class' not exists");
  80. // $id = call_user_func(array($class, 'id_prepare'), $id);
  81. // if(is_object($id))
  82. // bors_throw('Непонятно, что делать с id_prepare у новых объектов, когда они возвращают объект');
  83. $object = &object_new($class, $id);
  84. $object->data = $data;
  85. $object->changed_fields = $data;
  86. $object->set_owner_id(defval($data, 'owner_id', bors()->user_id()), true);
  87. $object->set_last_editor_id(bors()->user_id());
  88. $object->set_last_editor_ip(bors()->client()->ip());
  89. $object->set_last_editor_ua(bors()->client()->agent());
  90. $replace = popval($data, '*replace', false);
  91. if(!$object->set_fields($data, true, NULL, $need_check_data) && $need_check_data)
  92. {
  93. bors()->drop_changed_object($object);
  94. $object = NULL;
  95. return $object;
  96. }
  97. $object->set_attr('__replace_on_new_instance', $replace);
  98. $object->new_instance();
  99. $object->b2_configure();
  100. $object->set_is_loaded(true);
  101. return $object;
  102. }
  103. /**
  104. * @param bors_object $object
  105. */
  106. function bors_object_new_instance_db(&$object)
  107. {
  108. $tab = $object->table_name();
  109. if(!$tab)
  110. debug_exit("Try to get new db instance with empty main table");
  111. if(!$object->create_time(true))
  112. $object->set_create_time(time());
  113. if(!$object->modify_time(true))
  114. $object->set_modify_time(time());
  115. $object->set('owner_id', bors()->user_id());
  116. $object->set('owner_ip', bors()->client()->ip());
  117. $object->set('last_editor_id', bors()->user_id());
  118. $object->storage()->create($object);
  119. $object->changed_fields = array();
  120. }
  121. /**
  122. * @param bors_object $object
  123. */
  124. function bors_db_fields_init($object)
  125. {
  126. foreach($object->fields() as $db => $tables)
  127. foreach($tables as $tables => $fields)
  128. foreach($fields as $property => $db_field)
  129. $object->data[is_numeric($property) ? $db_field : $property] = NULL;
  130. }
  131. /** @var bors_global $GLOBALS */
  132. $GLOBALS['bors_global'] = NULL;
  133. /**
  134. * @return bors_global
  135. */
  136. function bors()
  137. {
  138. if(is_null(@$GLOBALS['bors_global']))
  139. if(class_exists('bors_global'))
  140. $GLOBALS['bors_global'] = new bors_global(NULL);
  141. else
  142. $GLOBALS['bors_global'] = false;
  143. return $GLOBALS['bors_global'];
  144. }
  145. function bors_clear() { $GLOBALS['bors_global'] = NULL; }
  146. function bors_exit($message = '')
  147. {
  148. bors_exit_handler($message);
  149. if(!config('do_not_exit'))
  150. exit();
  151. }
  152. function bors_exit_handler($message = '')
  153. {
  154. bors_function_include('debug/trace');
  155. bors_function_include('debug/hidden_log');
  156. bors_function_include('fs/file_put_contents_lock');
  157. if(!empty($GLOBALS['bors_data']['php_cache_content']))
  158. file_put_contents_lock(config('cache_dir') . '/functions.php', $GLOBALS['bors_data']['php_cache_content']);
  159. if(!empty($GLOBALS['bors_data']['classes_cache_content_updated']))
  160. {
  161. bors_debug::syslog('test', "write cache", false);
  162. file_put_contents_lock(config('cache_dir') . '/classes.php', $GLOBALS['bors_data']['classes_cache_content']);
  163. }
  164. static $bors_exit_doing = false;
  165. if($bors_exit_doing)
  166. return true;
  167. $bors_exit_doing = true;
  168. if($message)
  169. echo $message;
  170. if(config('cache_static') && $message)
  171. cache_static::drop(bors()->main_object());
  172. try
  173. {
  174. bors()->changed_save();
  175. }
  176. catch(Exception $e)
  177. {
  178. @header('HTTP/1.1 500 Internal Server Error');
  179. $error = bors_lib_exception::catch_html_code($e, ec("<div class=\"red_box\">Ошибка сохранения</div>"));
  180. }
  181. $error = error_get_last();
  182. if ($error['type'] == 1)
  183. {
  184. @header('HTTP/1.1 500 Internal Server Error');
  185. if($out_dir = config('debug_hidden_log_dir'))
  186. {
  187. @mkdir(config('debug_hidden_log_dir').'/errors');
  188. if(file_exists(config('debug_hidden_log_dir').'/errors'))
  189. {
  190. bors_debug::syslog('errors/'.date('c'), "Handled fatal error:
  191. errno={$error['type']}
  192. errstr={$error['message']}
  193. errfile={$error['file']}
  194. errline={$error['line']}", -1, ['append' => "stack\n=====\n".debug_trace(0, false)."\n\n_SERVER=".print_r($_SERVER, true)]);
  195. }
  196. }
  197. }
  198. if(!empty($GLOBALS['bors_data']['shutdown_handlers']))
  199. {
  200. foreach($GLOBALS['bors_data']['shutdown_handlers'] as $info)
  201. {
  202. if(!empty($info['arg']))
  203. call_user_func($info['callback'], $info['arg']);
  204. elseif(!empty($info['args']))
  205. call_user_func_array($info['callback'], $info['args']);
  206. else
  207. call_user_func($info['callback']);
  208. }
  209. }
  210. if(config('debug_mysql_trace'))
  211. {
  212. $dir = config('debug_hidden_log_dir').'/mysql-trace';
  213. @mkdir($dir);
  214. @chmod($dir, 0777);
  215. if(file_exists($dir))
  216. bors_debug::syslog('mysql-trace/'.date('c').'-'.rand(0,999999), "URL={$_SERVER['REQUEST_URI']}\n".print_r(@$GLOBALS['debug_mysql_trace'], true));
  217. }
  218. if(!empty($GLOBALS['debugbar_renderer']))
  219. echo $GLOBALS['debugbar_renderer']->render();
  220. return true;
  221. }
  222. function bors_parse_internal_uri($uri)
  223. {
  224. echo "parse $uri<Br/>";
  225. if(!preg_match('!^(\w+)://(.+)$!', $uri, $m))
  226. return array(NULL, NULL);
  227. if(preg_match('!^(\w+)/$!', $m[2], $mm))
  228. $m[2] = $mm[1];
  229. return array($m[1], $m[2]);
  230. }
  231. function bors_drop_global_caches()
  232. {
  233. unset($GLOBALS['bors_data']['global']['present']);
  234. unset($GLOBALS['HTS_GLOBAL_DATA']);
  235. unset($GLOBALS['bors_data']['cached_objects4']);
  236. }
  237. function bors_server_var($name, $default = NULL)
  238. {
  239. $sv = bors_find_first('bors_var_db', array('name' => $name, 'order' => '-create_time'));
  240. return $sv ? $sv->value() : $default;
  241. }
  242. function bors_set_server_var($name, $value, $keep_alive = -1)
  243. {
  244. $sv = bors_find_first('bors_var_db', array('name' => $name, 'order' => '-create_time'));
  245. if(!$sv)
  246. {
  247. $sv = object_new_instance('bors_var_db');
  248. $sv->set_name($name);
  249. }
  250. $sv->set_value($value);
  251. $sv->set_expire_time($keep_alive > 0 ? time() + $keep_alive : NULL);
  252. $sv->store();
  253. }
  254. function bors_stop_bots()
  255. {
  256. if(bors()->client()->is_bot())
  257. {
  258. @header("HTTP/1.0 404 Not Found");
  259. return go('http://balancer.ru/forum/', true);
  260. }
  261. return false;
  262. }
  263. function bors_throw($message)
  264. {
  265. static $level = 0;
  266. @header('HTTP/1.1 500 Internal Server Error');
  267. if(config('exceptions.kill_on_throw'))
  268. {
  269. bors_debug::syslog('exception-kill', $message);
  270. exit('Error. See in BORS logs');
  271. }
  272. if($level++ < 1)
  273. bors_debug::sepalog('exceptions-unknown', $message);
  274. throw new Exception($message);
  275. }
  276. /**
  277. * Возвращает результат применения метода get() к объекту, если он существует.
  278. * $def = NULL - в противном случае.
  279. * @param bors_object $object
  280. * @param string $property
  281. * @param mixed|null $def
  282. * @return mixed|null
  283. */
  284. function object_property($object, $property, $def = NULL)
  285. {
  286. if(!$object)
  287. return $def;
  288. if(is_object($object))
  289. {
  290. try
  291. {
  292. // Direct call like object_property($topic, 'title');
  293. if(preg_match('/^\w+$/', $property))
  294. return $object->get($property, $def);
  295. // Chain call like object_property($topic, 'time()->dmy()');
  296. else
  297. {
  298. $x = $object;
  299. foreach(explode('->', $property) as $p)
  300. {
  301. if(preg_match('/^(\w+)\(\)$/', $p, $m))
  302. {
  303. if(!is_object($x))
  304. return $def;
  305. $x = $x->get($m[1], $def);
  306. }
  307. else
  308. throw new \Exception("Unknown property format: '$property'");
  309. }
  310. return $x;
  311. }
  312. }
  313. catch(Exception $e)
  314. {
  315. return $def;
  316. }
  317. }
  318. return $def;
  319. }
  320. function object_property_args($object, $property, $args = array(), $def = NULL)
  321. {
  322. if(is_object($object))
  323. return call_user_func_array(array($object, $property), $args);
  324. return $def;
  325. }
  326. /**
  327. * Возвращает истину, если классы объектов и их ID совпадают.
  328. * @param bors_object $object1
  329. * @param bors_object $object2
  330. * @return bool
  331. */
  332. function bors_eq($object1, $object2)
  333. {
  334. return $object1->extends_class_name() == $object2->extends_class_name() && $object1->id() == $object2->id();
  335. }
  336. /**
  337. * Находит и возвращает объект по заданному классу и ID.
  338. * @param string $class_name
  339. * @param int|string|null $id
  340. * @return bors_object|null
  341. * @throws Exception
  342. */
  343. function bors_load($class_name, $id = NULL)
  344. {
  345. $object = object_load($class_name, $id);
  346. if(!$object && config('orm.is_strict') && !class_include($class_name))
  347. bors_throw("Not found class '{$class_name}' for load with id='{$id}'");
  348. return $object;
  349. }
  350. function bors_load_ex($class_name, $id, $attrs)
  351. {
  352. $memcache_time = popval($attrs, 'memcache');
  353. if(!array_key_exists('no_load_cache', $attrs) && !$memcache_time)
  354. $attrs['no_load_cache'] = true;
  355. if($memcache_time)
  356. {
  357. //if(config('is_developer')) var_dump($memcache_time);
  358. if(($memcache_instance = config('memcached_instance')))
  359. {
  360. debug_count_inc('memcached bors objects checks');
  361. unset($attrs['memcache']);
  362. $hash = 'bors_v'.config('memcached_tag').'_'.$class_name.'://'.$id;
  363. if($attrs)
  364. $hash .= '/'.serialize($attrs);
  365. if($x = unserialize($memcache_instance->get($hash)))
  366. {
  367. $updated = bors_class_loader_meta::cache_updated($x);
  368. if($x->can_cached() && !$updated)
  369. {
  370. debug_count_inc('memcached bors objects loads');
  371. return $x;
  372. }
  373. }
  374. }
  375. }
  376. $x = object_load($class_name, $id, $attrs);
  377. if($memcache_time && $memcache_instance)
  378. $memcache_instance->set($hash, serialize($x), 0, $memcache_time);
  379. return $x;
  380. }
  381. /**
  382. * @param string $uri
  383. * @return mixed|null
  384. */
  385. function bors_load_uri($uri)
  386. {
  387. static $loaded = array();
  388. if(!empty($loaded[$uri]))
  389. return $loaded[$uri];
  390. return $loaded[$uri] = object_load($uri);
  391. }
  392. /**
  393. * @param string $class_name
  394. * @param array $where
  395. * @return bors_object array
  396. */
  397. function bors_each($class_name, $where)
  398. {
  399. $storage = bors_foo($class_name)->storage();
  400. return $storage->each($class_name, $where);
  401. }
  402. function bors_new($class_name, $data = array())
  403. {
  404. if(!class_exists($class_name))
  405. throw new Exception("Неизвестный класс ".$class_name);
  406. if(is_null($data))
  407. return object_new($class_name); // Пустой объект
  408. return object_new_instance($class_name, $data); // Создаём объект
  409. }
  410. function bors_delete($class_name, $where)
  411. {
  412. //TODO: прописать в юниттесты оба варианта
  413. if(!array_key_exists('limit', $where))
  414. $where['limit'] = 1;
  415. if($where['limit'] === false)
  416. unset($where['limit']);
  417. foreach(bors_find_all($class_name, $where) as $x)
  418. $x->delete();
  419. }
  420. function bors_find($class_name)
  421. {
  422. return new bors_core_find($class_name);
  423. }
  424. /**
  425. * @param $class_name
  426. * @return bors_object
  427. * @throws Exception
  428. */
  429. function bors_foo($class_name)
  430. {
  431. require_once BORS_CORE.'/inc/functions/cache/global_key.php';
  432. require_once BORS_CORE.'/inc/functions/cache/set_global_key.php';
  433. if($cached_foo = global_key('___foos', $class_name))
  434. return $cached_foo;
  435. if(!class_exists($class_name))
  436. bors_throw("Unknown class $class_name in bors_foo");
  437. $object = new $class_name(NULL);
  438. if(method_exists($object, 'b2_configure'))
  439. $object->b2_configure();
  440. return set_global_key('___foos', $class_name, $object);
  441. }