PageRenderTime 76ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/broken-link-checker/includes/instances.php

https://bitbucket.org/lgorence/quickpress
PHP | 606 lines | 337 code | 101 blank | 168 comment | 57 complexity | 7ba887485f51a083e9ba432974c0d034 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-1.0
  1. <?php
  2. /**
  3. * @author W-Shadow
  4. * @copyright 2009
  5. */
  6. if (!class_exists('blcLinkInstance')) {
  7. class blcLinkInstance {
  8. //Object state
  9. var $is_new = false;
  10. //DB fields
  11. var $instance_id = 0;
  12. var $link_id = 0;
  13. var $container_id = 0;
  14. var $container_type = '';
  15. var $container_field = '';
  16. var $parser_type = '';
  17. var $link_text = '';
  18. var $link_context = '';
  19. var $raw_url = '';
  20. var $_container = null;
  21. var $_parser = null;
  22. var $_link = null;
  23. /**
  24. * blcLinkInstance::__construct()
  25. * Class constructor
  26. *
  27. * @param int|array $arg Either the instance ID or an associate array repreenting the instance's DB record. Should be NULL for new instances.
  28. * @return void
  29. */
  30. function __construct($arg = null){
  31. if (is_int($arg)){
  32. //Load an instance with ID = $arg from the DB.
  33. $q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d LIMIT 1", $arg);
  34. $arr = $wpdb->get_row( $q, ARRAY_A );
  35. if ( is_array($arr) ){ //Loaded successfully
  36. $this->set_values($arr);
  37. } else {
  38. //Link instance not found. The object is invalid.
  39. }
  40. } else if (is_array($arg)){
  41. $this->set_values($arg);
  42. //Is this a new instance?
  43. $this->is_new = empty($this->instance_id);
  44. } else {
  45. $this->is_new = true;
  46. }
  47. }
  48. /**
  49. * blcLinkInstance::blcLinkInstance()
  50. * Old-style constructor for PHP 4. Do not use.
  51. *
  52. * @param mixed $arg
  53. * @return void
  54. */
  55. function blcLinkInstance($arg = null){
  56. $this->__construct($arg);
  57. }
  58. /**
  59. * blcLinkInstance::set_values()
  60. * Set property values to the ones provided in an array (doesn't sanitize).
  61. *
  62. * @param array $arr An associative array
  63. * @return void
  64. */
  65. function set_values($arr){
  66. foreach( $arr as $key => $value ){
  67. $this->$key = $value;
  68. }
  69. }
  70. /**
  71. * Replace this instance's URL with a new one.
  72. * Warning : this shouldn't be called directly. Use blcLink->edit() instead.
  73. *
  74. * @param string $new_url
  75. * @param string $old_url
  76. * @return bool|WP_Error True on success, or an instance of WP_Error if something went wrong.
  77. */
  78. function edit($new_url, $old_url = ''){
  79. //Get the container that contains this link
  80. $container = $this->get_container();
  81. if ( is_null($container) ){
  82. return new WP_Error(
  83. 'container_not_found',
  84. sprintf(__("Container %s[%d] not found", 'broken-link-checker'), $this->container_type, $this->container_id)
  85. );
  86. }
  87. //Get the parser.
  88. $parser = $this->get_parser();
  89. if ( is_null($parser) ){
  90. return new WP_Error(
  91. 'parser_not_found',
  92. sprintf(__("Parser '%s' not found.", 'broken-link-checker'), $this->parser_type)
  93. );
  94. }
  95. //If the old URL isn't specified get it from the link record
  96. if ( empty($old_url) ){
  97. $old_url = $this->get_url();
  98. }
  99. //Attempt to modify the link(s)
  100. $result = $container->edit_link($this->container_field, $parser, $new_url, $old_url, $this->raw_url);
  101. if ( is_string($result) ){
  102. //If the modification was successful, the container will return
  103. //the new raw_url for the instance. Save the URL and return true,
  104. //indicating success.
  105. $this->raw_url = $result;
  106. return true;
  107. } elseif ( is_array($result) ){
  108. //More advanced containers/parsers may return an array of values to
  109. //modify several fields at once.
  110. $allowed_fields = array('raw_url', 'link_text', 'link_context');
  111. foreach($result as $key => $value){
  112. if ( in_array($key, $allowed_fields) ){
  113. $this->$key = $value;
  114. }
  115. }
  116. return true;
  117. } else {
  118. //Otherwise, it will return an error object. In this case we'll
  119. //just pass it back to the caller and let them sort it out.
  120. return $result;
  121. }
  122. }
  123. /**
  124. * blcLinkInstance::unlink()
  125. * Remove this instance from the post/blogroll/etc. Also deletes the appropriate DB record(s).
  126. *
  127. * @return bool|WP_Error
  128. */
  129. function unlink( $url = null ) {
  130. //Get the container that contains this link
  131. $container = $this->get_container();
  132. if ( is_null($container) ){
  133. return new WP_Error(
  134. 'container_not_found',
  135. sprintf(__("Container %s[%d] not found", 'broken-link-checker'), $this->container_type, $this->container_id)
  136. );
  137. }
  138. //Get the parser.
  139. $parser = $this->get_parser();
  140. if ( is_null($parser) ){
  141. return new WP_Error(
  142. 'parser_not_found',
  143. sprintf(__("Parser '%s' not found.", 'broken-link-checker'), $this->parser_type)
  144. );
  145. }
  146. //If the old URL isn't specified get it from the link record
  147. if ( empty($url) ){
  148. $url = $this->get_url();
  149. }
  150. //Attempt to remove the link(s)
  151. return $container->unlink($this->container_field, $parser, $url, $this->raw_url);
  152. }
  153. /**
  154. * Remove the link instance record from database. Doesn't affect the thing that contains the link.
  155. *
  156. * @return mixed 1 on success, 0 if the instance wasn't found, false on error
  157. */
  158. function forget(){
  159. global $wpdb;
  160. if ( !empty($this->instance_id) ) {
  161. $rez = $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d", $this->instance_id) );
  162. return $rez;
  163. } else {
  164. return false;
  165. }
  166. }
  167. /**
  168. * Store the link instance in the database.
  169. * Saving the instance will also implicitly save the link record associated with it, if it wasn't already saved.
  170. *
  171. * @return bool TRUE on success, FALSE on error
  172. */
  173. function save(){
  174. global $wpdb;
  175. //Refresh the locally cached link & container properties, in case
  176. //the objects have changed since they were set.
  177. if ( !is_null($this->_link) ){
  178. //If we have a link object assigned, but it's new, it won't have a DB ID yet.
  179. //We need to save the link to get the ID and be able to maintain the link <-> instance
  180. //association.
  181. if ( $this->_link->is_new ){
  182. $rez = $this->_link->save();
  183. if ( !$rez ){
  184. return false;
  185. }
  186. }
  187. $this->link_id = $this->_link->link_id;
  188. }
  189. if ( !is_null($this->_container) ){
  190. $this->container_type = $this->_container->container_type;
  191. $this->container_id = $this->_container->container_id;
  192. }
  193. //If the link is new, insert a new row into the DB. Otherwise update the existing row.
  194. if ( $this->is_new ){
  195. $q = "
  196. INSERT INTO {$wpdb->prefix}blc_instances
  197. ( link_id, container_type, container_id, container_field, parser_type, link_text, link_context, raw_url )
  198. VALUES( %d, %s, %d, %s, %s, %s, %s, %s )";
  199. $q = $wpdb->prepare(
  200. $q,
  201. $this->link_id,
  202. $this->container_type,
  203. $this->container_id,
  204. $this->container_field,
  205. $this->parser_type,
  206. $this->link_text,
  207. $this->link_context,
  208. $this->raw_url
  209. );
  210. $rez = $wpdb->query($q) !== false;
  211. if ($rez){
  212. $this->instance_id = $wpdb->insert_id;
  213. //If the instance was successfully saved then it's no longer "new".
  214. $this->is_new = !$rez;
  215. }
  216. return $rez;
  217. } else {
  218. $q = "UPDATE {$wpdb->prefix}blc_instances
  219. SET
  220. link_id = %d,
  221. container_type = %s,
  222. container_id = %d,
  223. container_field = %s,
  224. parser_type = %s,
  225. link_text = %s,
  226. link_context = %s,
  227. raw_url = %s
  228. WHERE instance_id = %d";
  229. $q = $wpdb->prepare(
  230. $q,
  231. $this->link_id,
  232. $this->container_type,
  233. $this->container_id,
  234. $this->container_field,
  235. $this->parser_type,
  236. $this->link_text,
  237. $this->link_context,
  238. $this->raw_url,
  239. $this->instance_id
  240. );
  241. $rez = $wpdb->query($q) !== false;
  242. if ($rez){
  243. //FB::info($this, "Instance updated");
  244. } else {
  245. //FB::error("DB error while updating instance {$this->instance_id} : {$wpdb->last_error}");
  246. }
  247. return $rez;
  248. }
  249. }
  250. /**
  251. * Get the URL associated with this instance.
  252. *
  253. * @return string The associated URL, or an empty string if the instance is currently not assigned to any link.
  254. */
  255. function get_url(){
  256. $link = $this->get_link();
  257. if ( !is_null($link) ){
  258. return $link->url;
  259. } else {
  260. return '';
  261. }
  262. }
  263. /**
  264. * Get the container object associated with this link instance
  265. *
  266. * @return blcContainer|null
  267. */
  268. function get_container(){
  269. if( is_null($this->_container) ){
  270. $this->_container = blcContainerHelper::get_container( array($this->container_type, $this->container_id) );
  271. }
  272. return $this->_container;
  273. }
  274. /**
  275. * Set a new container for the link instance.
  276. *
  277. * @param blcContainer $new_container
  278. * @param string $field
  279. * @return void
  280. */
  281. function set_container(&$new_container, $field = ''){
  282. $this->_container = &$new_container;
  283. $this->container_field = $field;
  284. if( !is_null($new_container) ){
  285. $this->container_type = $new_container->container_type;
  286. $this->container_id = $new_container->container_id;
  287. } else {
  288. $this->container_type = '';
  289. $this->container_id = 0;
  290. }
  291. }
  292. /**
  293. * Get the parser associated with this link instance.
  294. *
  295. * @return blcParser|null
  296. */
  297. function get_parser(){
  298. if ( is_null($this->_parser) ){
  299. $this->_parser = blcParserHelper::get_parser($this->parser_type);
  300. }
  301. return $this->_parser;
  302. }
  303. /**
  304. * Set a new parser fo this link instance.
  305. *
  306. * @param blcParser|null $new_parser
  307. * @return void
  308. */
  309. function set_parser(&$new_parser){
  310. $this->_parser = &$new_parser;
  311. if ( is_null($new_parser) ){
  312. $this->parser_type = '';
  313. } else {
  314. $this->parser_type = $new_parser->parser_type;
  315. }
  316. }
  317. /**
  318. * Get the link object associated with this link intance.
  319. *
  320. * @return blcLink|null
  321. */
  322. function get_link(){
  323. if ( !is_null($this->_link) ){
  324. return $this->_link;
  325. }
  326. if ( empty($this->link_id) ) {
  327. return null;
  328. }
  329. $this->_link = new blcLink($this->link_id);
  330. return $this->_link;
  331. }
  332. /**
  333. * Set the link associated with this link instance.
  334. *
  335. * @param blcLink $new_link
  336. * @return void
  337. */
  338. function set_link($new_link){
  339. $this->_link = $new_link;
  340. if ( is_null($new_link) ){
  341. $this->link_id = 0;
  342. } else {
  343. $this->link_id = $new_link->link_id;
  344. }
  345. }
  346. /**
  347. * Get the link text for printing in the "Broken Links" table.
  348. *
  349. * @param string $context How to filter the link text. Optional, defaults to 'display'.
  350. * @return string HTML
  351. */
  352. function ui_get_link_text($context = 'display'){
  353. $parser = $this->get_parser();
  354. if ( !is_null($parser) ){
  355. $text = $parser->ui_get_link_text($this, $context);
  356. } else {
  357. $text = strip_tags($this->link_text);
  358. }
  359. if ( empty($text) ){
  360. $text = "<em>(None)</em>";
  361. }
  362. return $text;
  363. }
  364. /**
  365. * Get action links that should be displayed in the "Source" column of the "Broken Links" table.
  366. *
  367. * @return array An array of HTML links.
  368. */
  369. function ui_get_action_links(){
  370. //The container is responsible for generating the links.
  371. $container = $this->get_container();
  372. if ( !is_null($container) ){
  373. return $container->ui_get_action_links($this->container_field);
  374. } else {
  375. //No valid container = no links.
  376. return array();
  377. }
  378. }
  379. /**
  380. * Get the HTML describing the "source" of the instance. For example, for links found in posts,
  381. * this could be the post title.
  382. *
  383. * @param string $context How to filter the output. Optional, defaults to 'display'.
  384. * @return string HTML
  385. */
  386. function ui_get_source($context = 'display'){
  387. //The container is also responsible for generating the "Source" column HTML.
  388. $container = $this->get_container();
  389. if ( !is_null($container) ){
  390. return $container->ui_get_source($this->container_field, $context);
  391. } else {
  392. //No valid container = generate some bare-bones debug output.
  393. return sprintf('%s[%d] : %s', $this->container_type, $this->container_id, $this->container_field);
  394. }
  395. }
  396. }
  397. /**
  398. * Get all link instances associated with one or more links.
  399. *
  400. * @param array $link_ids Array of link IDs.
  401. * @param string $purpose An optional code indicating how the instances will be used. Available predefined constants : BLC_FOR_DISPLAY, BLC_FOR_EDITING
  402. * @param bool $load_containers Preload containers regardless of purpose. Defaults to false.
  403. * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose. Defaults to false.
  404. * @param bool $include_invalid Include instances that refer to not-loaded containers or parsers. Defaults to false.
  405. * @return array An array indexed by link ID. Each item of the array will be an array of blcLinkInstance objects.
  406. */
  407. function blc_get_instances( $link_ids, $purpose = '', $load_containers = false, $load_wrapped_objects = false, $include_invalid = false ){
  408. global $wpdb;
  409. if ( empty($link_ids) ){
  410. return array();
  411. }
  412. $link_ids_in = implode(', ', $link_ids);
  413. $q = "SELECT * FROM {$wpdb->prefix}blc_instances WHERE link_id IN ($link_ids_in)";
  414. //Skip instances that reference containers or parsers that aren't currently loaded
  415. if ( !$include_invalid ){
  416. $manager = blcModuleManager::getInstance();
  417. $active_containers = $manager->get_escaped_ids('container');
  418. $active_parsers = $manager->get_escaped_ids('parser');
  419. $q .= " AND container_type IN ({$active_containers}) ";
  420. $q .= " AND parser_type IN ({$active_parsers}) ";
  421. }
  422. $results = $wpdb->get_results($q, ARRAY_A);
  423. if ( empty($results) ) {
  424. return array();
  425. }
  426. //Also retrieve the containers, if it could be useful.
  427. $load_containers = $load_containers || in_array( $purpose, array(BLC_FOR_DISPLAY, BLC_FOR_EDITING) );
  428. if ( $load_containers ){
  429. //Collect a list of (container_type, container_id) pairs
  430. $container_ids = array();
  431. foreach($results as $result){
  432. array_push(
  433. $container_ids,
  434. array( $result['container_type'], intval($result['container_id']) )
  435. );
  436. }
  437. $containers = blcContainerHelper::get_containers($container_ids, $purpose, '', $load_wrapped_objects);
  438. }
  439. //Create an object for each instance and group them by link ID
  440. $instances = array();
  441. foreach ($results as $result){
  442. $instance = new blcLinkInstance($result);
  443. //Assign a container to the link instance, if available
  444. if( $load_containers && !empty($containers) ){
  445. $key = $instance->container_type . '|' . $instance->container_id;
  446. if( isset($containers[$key]) ){
  447. $instance->_container = $containers[$key];
  448. }
  449. }
  450. if ( isset($instances[$instance->link_id]) ){
  451. array_push( $instances[$instance->link_id], $instance );
  452. } else {
  453. $instances[$instance->link_id] = array($instance);
  454. }
  455. }
  456. return $instances;
  457. }
  458. /**
  459. * Get the number of instances that reference only currently loaded containers and parsers.
  460. *
  461. * @return int
  462. */
  463. function blc_get_usable_instance_count(){
  464. global $wpdb;
  465. $q = "SELECT COUNT(instance_id) FROM {$wpdb->prefix}blc_instances WHERE 1";
  466. //Skip instances that reference containers or parsers that aren't currently loaded
  467. $manager = blcModuleManager::getInstance();
  468. $active_containers = $manager->get_escaped_ids('container');
  469. $active_parsers = $manager->get_escaped_ids('parser');
  470. $q .= " AND container_type IN ({$active_containers}) ";
  471. $q .= " AND parser_type IN ({$active_parsers}) ";
  472. return $wpdb->get_var($q);
  473. }
  474. /**
  475. * Remove instances that reference invalid containers or containers/parsers that are not currently loaded
  476. *
  477. * @return bool
  478. */
  479. function blc_cleanup_instances(){
  480. global $wpdb;
  481. global $blclog;
  482. //Delete all instances that reference non-existent containers
  483. $q = "DELETE instances.*
  484. FROM
  485. {$wpdb->prefix}blc_instances AS instances LEFT JOIN {$wpdb->prefix}blc_synch AS synch
  486. ON instances.container_type = synch.container_type AND instances.container_id = synch.container_id
  487. WHERE
  488. synch.container_id IS NULL";
  489. $rez = $wpdb->query($q);
  490. $blclog->log(sprintf('... %d instances deleted', $wpdb->rows_affected));
  491. //Delete instances that reference containers and parsers that are no longer active
  492. $manager = blcModuleManager::getInstance();
  493. $active_containers = $manager->get_escaped_ids('container');
  494. $active_parsers = $manager->get_escaped_ids('parser');
  495. $q = "DELETE instances.*
  496. FROM {$wpdb->prefix}blc_instances AS instances
  497. WHERE
  498. instances.container_type NOT IN ({$active_containers}) OR
  499. instances.parser_type NOT IN ({$active_parsers})";
  500. $rez2 = $wpdb->query($q);
  501. $blclog->log(sprintf('... %d more instances deleted', $wpdb->rows_affected));
  502. return ($rez !== false) && ($rez2 !== false);
  503. }
  504. }//class_exists
  505. ?>