| [ Index ] | [ Index ] [ Classes ] [ Functions ] [ Variables ] [ Constants ] |
PHP Cross Reference of TXP stable 4.0.6 |
||
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 $HeadURL: http://svn.textpattern.com/releases/4.0.6/source/textpattern/lib/txplib_wrapper.php $ 5 $LastChangedRevision: 2800 $ 6 */ 7 8 /** 9 * Textpattern Wrapper Class for Textpattern 4.0.x 10 * 11 * Main goal for this class is to be used as a textpattern data wrapper by 12 * any code which needs to have access to the textpattern articles data, 13 * like XML-RPC, Atom, Moblogging or other external implementations. 14 * 15 * @link http://txp.kusor.com/wrapper 16 * @author Pedro Palazon - http://kusor.net/ 17 * @copyright 2005-2008 The Textpattern Development Team - http://textpattern.com 18 */ 19 20 # This class requires to include some Textpattern files in order to work properly. 21 # See RPC Server implementation to view an example of the required files and predefined variables. 22 23 if (!defined('txpath')) die('txpath is undefined.'); 24 include_once txpath.'/include/txp_auth.php'; 25 # Include constants.php? 26 if (!defined('LEAVE_TEXT_UNTOUCHED')) define('LEAVE_TEXT_UNTOUCHED', 0); 27 if (!defined('USE_TEXTILE')) define('USE_TEXTILE', 1); 28 if (!defined('CONVERT_LINEBREAKS')) define('CONVERT_LINEBREAKS', 2); 29 30 class TXP_Wrapper 31 { 32 /** 33 * @var string The current user 34 * 35 * Remeber to use allways $this->txp_user when checking for permissions with this class 36 */ 37 var $txp_user = null; 38 /** 39 * @var boolean Is the user authenticated 40 */ 41 var $loggedin = false; 42 /** 43 * @var array Predefined Textpattern vars to be populated 44 */ 45 var $vars = array( 46 'ID','Title','Title_html','Body','Body_html','Excerpt','Excerpt_html','textile_excerpt','Image', 47 'textile_body', 'Keywords','Status','Posted','Section','Category1','Category2', 48 'Annotate','AnnotateInvite','AuthorID','Posted','override_form', 49 'url_title','custom_1','custom_2','custom_3','custom_4','custom_5', 50 'custom_6','custom_7','custom_8','custom_9','custom_10' 51 ); 52 53 //Class constructor 54 /** 55 * Class constructor 56 * @param string $txp_user the user login name 57 * @param strign $txpass user password 58 * 59 * @see _validate 60 */ 61 function TXP_Wrapper($txp_user, $txpass = NULL) 62 { 63 if ($this->_validate($txp_user, $txpass)) 64 { 65 $this->txp_user = $txp_user; 66 $this->loggedin = true; 67 } 68 } 69 70 //Delete the article given the id 71 /** 72 * Delete the article given the id 73 * @param mixed(string|integer) $article_id the ID of the article to delete 74 * @return boolean true on success deletion 75 */ 76 function deleteArticleID($article_id) 77 { 78 $article_id = assert_int($article_id); 79 if ($this->loggedin && has_privs('article.delete', $this->txp_user)) { 80 return safe_delete('textpattern', "ID = $article_id"); 81 } 82 elseif ($this->loggedin && has_privs('article.delete.own', $this->txp_user)) 83 { 84 $r = safe_field('ID', 'textpattern', "ID = $article_id AND AuthorID='".doSlash($this->txp_user)."'"); 85 if ($r || has_privs('article.delete', $this->txp_user)) 86 { 87 return safe_delete('textpattern', "ID = $article_id"); 88 } 89 } 90 return false; 91 } 92 93 //Retrieves a list of articles matching the given criteria 94 /** 95 * Retrieves a list of articles matching the given criteria 96 * @param string $what SQL column names to retrieve 97 * @param string $where SQL condition to match 98 * @param string $offset SQL offset 99 * @param string $limit SQL limit 100 * @param boolean $slash escape SQL column names and condition 101 * @return mixed array on success, false on failure 102 */ 103 function getArticleList($what='*', $where='1', $offset='0', $limit='10', $slash=true) 104 { 105 106 if ($this->loggedin && has_privs('article.edit.own', $this->txp_user)) 107 { 108 $offset = assert_int($offset); 109 $limit = assert_int($limit); 110 111 if ($slash) { 112 $where = doSlash($where); 113 $what = doSlash($what); 114 } 115 116 if (has_privs('article.edit', $this->txp_user)) { 117 $rs = safe_rows_start($what, 'textpattern', $where." order by Posted desc LIMIT $offset, $limit"); 118 }else{ 119 $rs = safe_rows_start($what, 'textpattern', $where." AND AuthorID='".doSlash($this->txp_user)."' order by Posted desc LIMIT $offset, $limit"); 120 } 121 $out = array(); 122 if ($rs) 123 { 124 while ($a = nextRow($rs)) 125 { 126 $out[]= $a; 127 } 128 } 129 return $out; 130 } 131 return false; 132 } 133 134 //Retrieves an article matching the given criteria 135 /** 136 * Retrieves an article matching the given criteria 137 * @param string $what SQL column names to retrieve 138 * @param string $where SQL condition to match 139 * @param boolean $slash escape SQL column names and condition 140 * @return mixed array on success, false on failure 141 */ 142 function getArticle($what='*', $where='1', $slash=true) 143 { 144 if ($this->loggedin && has_privs('article.edit.own', $this->txp_user)) 145 { 146 if ($slash) { 147 $what = doSlash($what); 148 $where = doSlash($where); 149 } 150 // Higer user groups should be able to edit any article 151 if (has_privs('article.edit', $this->txp_user)) { 152 return safe_row($what, 'textpattern', $where); 153 }else { 154 // While restricted users should be able to edit their own articles only 155 return safe_row($what, 'textpattern', $where." AND AuthorID='".doSlash($this->txp_user)."'"); 156 } 157 } 158 return false; 159 } 160 161 //Same thing, but handy shortcut known the ID 162 /** 163 * Same thing, but handy shortcut known the ID 164 * @param mixed(string|integer) $article_id the ID of the article 165 * @param string $what SQL column names to retrieve 166 * @return mixed array on success, false on failure 167 */ 168 function getArticleID($article_id, $what='*') 169 { 170 if ($this->loggedin && has_privs('article.edit.own', $this->txp_user)) 171 { 172 $article_id = assert_int($article_id); 173 if (has_privs('article.edit', $this->txp_user)) { 174 return safe_row(doSlash($what), 'textpattern', "ID = $article_id"); 175 }else{ 176 return safe_row(doSlash($what), 'textpattern', "ID = $article_id AND AuthorID='".doSlash($this->txp_user)."'"); 177 } 178 } 179 return false; 180 } 181 182 //Updates an existing article 183 /** 184 * Updates an existing article 185 * @param array $params the article fields to update 186 * @param mixed(string|integer) $article_id the ID of the article to update 187 * @return mixed integer article id on success, false on failure 188 * @see _setArticle 189 */ 190 function updateArticleID($article_id, $params) 191 { 192 $article_id = assert_int($article_id); 193 194 $r = safe_field('ID', 'textpattern', "AuthorID='".doSlash($this->txp_user)."' AND ID = $article_id"); 195 196 if ($this->loggedin && $r && has_privs('article.edit.own', $this->txp_user)) 197 { //Unprivileged user 198 //Check if can edit published arts 199 $r = assert_int($r); 200 $oldstatus = safe_field('Status', 'textpattern', "ID = $r"); 201 if (($oldstatus=='4' || $oldstatus == '5') && !has_privs('article.edit.published', $this->txp_user)) return false; 202 //If can, let's go 203 return $this->_setArticle($params, $article_id); 204 } 205 elseif ($this->loggedin && has_privs('article.edit', $this->txp_user)) 206 {//Admin editing. Desires are behest. 207 return $this->_setArticle($params, $article_id); 208 } 209 210 return false; 211 } 212 213 //Creates a new article 214 /** 215 * Creates a new article 216 * @param array $params the article fields 217 * @return mixed integer article id on success, false on failure 218 * @see _setArticle 219 */ 220 function newArticle($params) 221 { 222 if ($this->loggedin && has_privs('article', $this->txp_user)) 223 { 224 //Prevent junior authors to publish articles 225 if (($params['Status']=='4' || $params['Status']=='5') && !has_privs('article.publish', $this->txp_user)) 226 { 227 $params['Status']='3'; 228 } 229 230 return $this->_setArticle($params); 231 } 232 return false; 233 } 234 235 //Get full sections information 236 /** 237 * Get full sections information 238 * @return mixed array on success, false on failure 239 */ 240 function getSectionsList() 241 { 242 if ($this->loggedin && has_privs('article', $this->txp_user)) 243 { 244 return safe_rows('*', 'txp_section',"name!='default'"); 245 } 246 return false; 247 } 248 249 //Get one section 250 /** 251 * Get one section 252 * @param string $name the section name 253 * @return mixed array on success, false on failure 254 */ 255 function getSection($name) 256 { 257 if ($this->loggedin && has_privs('article', $this->txp_user)) 258 { 259 $name = doSlash($name); 260 return safe_row('*', 'txp_section',"name='$name'"); 261 } 262 return false; 263 } 264 265 //Get full categories information 266 /** 267 * Get full categories information 268 * @return mixed array on success, false on failure 269 */ 270 function getCategoryList() 271 { 272 if ($this->loggedin && has_privs('article', $this->txp_user)) 273 { 274 return safe_rows('*', 'txp_category',"name!='root' AND type='article'"); 275 } 276 return false; 277 } 278 /** 279 * Get one category by category name 280 * @param string $name the category name 281 * @return mixed array on success, false on failure 282 */ 283 function getCategory($name) 284 { 285 if ($this->loggedin && has_privs('article', $this->txp_user)) 286 { 287 $name = doSlash($name); 288 return safe_row('*', 'txp_category',"name='$name' AND type='article'"); 289 } 290 return false; 291 } 292 /** 293 * Get one category by category id 294 * @param mixed(string|integer) $id category id 295 * @return mixed array on success, false on failure 296 */ 297 function getCategoryID($id) 298 { 299 if ($this->loggedin && has_privs('article', $this->txp_user)) 300 { 301 $id = assert_int($id); 302 return safe_row('*', 'txp_category',"id = $id"); 303 } 304 return false; 305 } 306 /** 307 * Get one category by category title 308 * @param string $title the category title 309 * @return mixed array on success, false on failure 310 */ 311 function getCategoryTitle($title) 312 { 313 if ($this->loggedin && has_privs('article', $this->txp_user)) 314 { 315 $title = doSlash($title); 316 return safe_row('*', 'txp_category',"title='$title' AND type='article'"); 317 } 318 return false; 319 } 320 //Get full information for current user 321 /** 322 * Get full information for current user 323 * @return mixed array on success, false on failure 324 */ 325 function getUser() 326 { 327 if ($this->loggedin) 328 { 329 return safe_row('*', 'txp_users',"name='$this->txp_user'"); 330 } 331 return false; 332 } 333 334 //Retrieves a template with the given name 335 /** 336 * Retrieves a template with the given name 337 * @param string $name the template name 338 */ 339 function getTemplate($name) 340 { 341 if ($this->loggedin && has_privs('page', $this->txp_user)) 342 { 343 $name = doSlash($name); 344 return safe_field('user_html', 'txp_page', "name='$name'"); 345 } 346 return false; 347 } 348 //Updates a template with the given name 349 /** 350 * Updates a template with the given name 351 * @param string $name the template name 352 * @param string $html the template contents 353 * @return boolean true on success 354 */ 355 function setTemplate($name, $html) 356 { 357 if ($this->loggedin && has_privs('page', $this->txp_user)) 358 { 359 $name = doSlash($name); 360 $html = doSlash($html); 361 return safe_update('txp_page', "user_html='$html'", "name='$name'"); 362 } 363 } 364 365 // Intended to update article non content fields, like categories 366 // section or Keywords 367 /** 368 * Intended to update article non content fields, like categories, section or Keywords 369 * @param mixed(string|integer) $article_id the ID of the article to update 370 * @param string $field the name of the field to update 371 * @param mixed $value desired value for that field 372 * @return boolean true on success 373 */ 374 function updateArticleField($article_id, $field, $value) 375 { 376 $disallow = array('Body','Body_html','Title','Title_html','Excerpt', 377 'Excerpt_html','textile_excerpt','textile_body','LastMod', 378 'LastModID', 'feed_time', 'uid'); 379 if ($this->loggedin && has_privs('article.edit', $this->txp_user) && !in_array(doSlash($field),$disallow)) 380 { 381 $field = doSlash($field); 382 $value = doSlash($value); 383 384 if($field == 'Posted') 385 { 386 $value = strtotime($value)-tz_offset(); 387 $value = "from_unixtime($value)"; 388 $sql = "Posted = $value"; 389 }elseif ($field == 'Status'){ 390 $value = assert_int($value); 391 if (!has_privs('article.publish', $this->txp_user) && $value >=4) $value = 3; 392 $sql = "Status = $value"; 393 }else{ 394 $sql = "$field='$value'"; 395 } 396 397 398 $sql.= ", LastMod = now(), 399 LastModID = '$this->txp_user'"; 400 $article_id = assert_int($article_id); 401 $rs = safe_update('textpattern', $sql, "ID = $article_id"); 402 //Do not update lastmod pref here. No new content at all. 403 return $rs; 404 } 405 return false; 406 } 407 408 // ------------------------------------------------------------- 409 // Private. Real action takes place here. 410 // ------------------------------------------------------------- 411 /** 412 * Executes the real action for @see udpateArticleId and @see newArticle 413 * @param array $incoming containing the desired article fields 414 * @param mixed(string|integer) $article_id the ID of the article to update 415 * @return mixed integer article id on success, false otherwise 416 * @access private 417 */ 418 function _setArticle($incoming, $article_id = null) 419 { 420 global $txpcfg; 421 422 $prefs = get_prefs(); 423 424 extract($prefs); 425 426 if ($article_id!==null) { 427 $article_id = assert_int($article_id); 428 } 429 430 //All validation rules assumed to be passed before this point. 431 //Do content processing here 432 433 434 $incoming_with_markup = $this->textile_main_fields($incoming, $use_textile); 435 436 $incoming['Title'] = $incoming_with_markup['Title']; 437 438 if (empty($incoming['Body_html']) && !empty($incoming['Body'])) 439 { 440 $incoming['Body_html'] = $incoming_with_markup['Body_html']; 441 } 442 443 if (empty($incoming['Excerpt_html']) && !empty($incoming['Excerpt'])) 444 { 445 $incoming['Excerpt_html'] = $incoming_with_markup['Excerpt_html']; 446 } 447 448 unset($incoming_with_markup); 449 450 if (empty($incoming['Posted'])) { 451 if ($article_id===null) { 452 $when = (!$article_id)? 'now()': ''; 453 $incoming['Posted'] = $when; 454 }else{ 455 # do not override post time for existing articles unless Posted is present 456 unset($incoming['Posted']); 457 } 458 } else { 459 $when = strtotime($incoming['Posted'])-tz_offset(); 460 $when = "from_unixtime($when)"; 461 } 462 463 464 if ($incoming['Title'] || $incoming['Body'] || $incoming['Excerpt']) { 465 //Build SQL then and run query 466 467 //Prevent data erase if not defined on the update action 468 //but it was on the DB from a previous creation/edition time 469 if ($article_id){ 470 471 $old = safe_row('*','textpattern', "ID = $article_id"); 472 //Status should be defined previously. Be sure of that. 473 if (!has_privs('article.publish', $this->txp_user) && $incoming['Status']==4 && $old['Status']!=4) $incoming['Status'] = 3; 474 475 foreach ($old as $key=>$val) 476 { 477 if (!isset($incoming[$key])) $incoming[$key] = $val; 478 } 479 480 }else{ 481 //Status should be defined previously. Be sure of that. 482 if (!has_privs('article.publish', $this->txp_user) && $incoming['Status']==4) $incoming['Status'] = 3; 483 } 484 485 if (empty($incoming['Section']) && $article_id) 486 { 487 $incoming['Section'] = safe_field('Section','textpattern',"ID = $article_id"); 488 } 489 490 $incoming = $this->_check_keys($incoming, 491 array( 492 'AuthorID' => $this->txp_user, 493 'Annotate' => $comments_on_default, 494 'AnnotateInvite' => $comments_default_invite, 495 'textile_body' => $use_textile, 496 'textile_excerpt' => $use_textile, 497 'url_title' => stripSpace($incoming['Title']) 498 ) 499 ); 500 501 //Build the SQL query 502 $sql = array(); 503 504 foreach ($incoming as $key => $val) 505 { 506 if($key == 'Posted' && $val == 'now()') 507 { 508 $sql[]= "$key = $val"; 509 }elseif ($key!='ID' && $key!='uid' && $key!='feed_time' && $key!='LastMod' && $key!='LastModID') 510 { 511 $sql[]= "$key = '".doSlash($val)."'"; 512 } 513 } 514 $sql[]= 'LastMod = now()'; 515 $sql[]= "LastModID = '".doSlash($this->txp_user)."'"; 516 if (!$article_id) $sql[]= "uid = '".doSlash(md5(uniqid(rand(),true)))."'"; 517 if (!$article_id) 518 { 519 if (empty($incoming['Posted'])) 520 { 521 $sql[]= "feed_time = curdate()"; 522 }else{ 523 $when = strtotime($incoming['Posted'])-tz_offset(); 524 $when = strftime("%Y-%m-%d", $when); 525 $sql[]= "feed_time ='".doSlash($when)."'"; 526 } 527 } 528 $sql = join(', ', $sql); 529 530 $rs = ($article_id)? 531 safe_update('textpattern', $sql, "ID = $article_id"): 532 safe_insert('textpattern', $sql); 533 534 $oldstatus = ($article_id)? $old['Status'] : ''; 535 536 if (!$article_id && $rs) $article_id = $rs; 537 538 if (($incoming['Status']>=4 && !$article_id) || ($oldstatus!=4 && $article_id)) { 539 safe_update("txp_prefs", "val = now()", "name = 'lastmod'"); 540 //@$this->_sendPings(); 541 } 542 return $article_id; 543 } 544 545 return false; 546 } 547 548 // ------------------------------------------------------------- 549 // Private 550 // ------------------------------------------------------------- 551 552 /** 553 * Attemp to validates the user with the provided password 554 * or takes it from the global scope, assuming the user is logged in 555 * @param string $user login name of the user to validate 556 * @param string(optional) $password for that user 557 * @access private 558 * @return boolean, true if user is logged in 559 */ 560 function _validate($user,$password = NULL) { 561 562 if ($password!==NULL) 563 { 564 $r = txp_validate($user, $password); 565 }else{ 566 $r = true; 567 } 568 if ($r) { 569 // update the last access time 570 $safe_user = addslashes($user); 571 safe_update("txp_users", "last_access = now()", "name = '$safe_user'"); 572 return true; 573 } 574 return false; 575 } 576 577 // ------------------------------------------------------------- 578 // Keep this apart for now. Maybe future changes ob this? 579 // ------------------------------------------------------------- 580 // This is duplicated code from txp_article.php too 581 582 function _sendPings() 583 { 584 global $prefs, $txpcfg; 585 extract($prefs); 586 587 include_once txpath.'/lib/IXRClass.php'; 588 589 if ($ping_textpattern_com) { 590 $tx_client = new IXR_Client('http://textpattern.com/xmlrpc/'); 591 $tx_client->query('ping.Textpattern', $sitename, hu); 592 } 593 594 if ($ping_weblogsdotcom==1) { 595 $wl_client = new IXR_Client('http://rpc.pingomatic.com/'); 596 $wl_client->query('weblogUpdates.ping', $sitename, hu); 597 } 598 } 599 600 /** 601 * Check if the given parameters are the appropiated ones for the articles 602 * @access private 603 * @param $incoming array the incoming associative array 604 * @param $default associative array containing default values for the desired keys 605 * @return array properly striped off the fields which don't match the defined ones. 606 */ 607 function _check_keys($incoming, $default = array()) 608 { 609 $out = array(); 610 # strip off unsuited keys 611 foreach ($incoming as $key => $val) 612 { 613 if (in_array($key, $this->vars)) 614 { 615 $out[$key] = $val; 616 } 617 } 618 619 foreach ($this->vars as $def_key) 620 { 621 # Add those ones inexistent in the incoming array 622 if (!array_key_exists($def_key,$out)) 623 { 624 $out[$def_key] = ''; 625 } 626 # setup the provided default value, if any, only when the incoming value is empty 627 if (array_key_exists($def_key, $default) && empty($out[$def_key])) 628 { 629 $out[$def_key] = $default[$def_key]; 630 } 631 } 632 return $out; 633 } 634 635 /** 636 * Apply textile to the main article fields 637 * (duplicated from txp_article.php!) 638 * @param array containing the $incoming vars array 639 * @param global use_textile preference 640 * @return array the same one containing the formatted fields 641 */ 642 643 function textile_main_fields($incoming, $use_textile = 1) 644 { 645 global $txpcfg; 646 647 include_once txpath.'/lib/classTextile.php'; 648 $textile = new Textile(); 649 650 if (!empty($event) and $event == 'article') 651 { 652 $incoming['Title_plain'] = $incoming['Title']; 653 } 654 655 if ($incoming['textile_body'] == USE_TEXTILE) 656 { 657 $incoming['Title'] = $textile->TextileThis($incoming['Title'],'',1); 658 } 659 660 $incoming['url_title'] = preg_replace('|[\x00-\x1f#%+/?\x7f]|', '', $incoming['url_title']); 661 662 $incoming['Body_html'] = TXP_Wrapper::format_field($incoming['Body'],$incoming['textile_body'],$textile); 663 664 $incoming['Excerpt_html'] = TXP_Wrapper::format_field($incoming['Excerpt'],$incoming['textile_excerpt'],$textile); 665 666 return $incoming; 667 } 668 669 # Try to avoid code duplication when formating fields. 670 /** 671 * Apply markup to a given fields 672 * 673 * @param string $field raw field contents 674 * @param integer $format format type to apply 675 * @param object $textile instance 676 * @return string html formated field 677 */ 678 679 function format_field($field, $format,$textile) 680 { 681 switch ($format){ 682 case LEAVE_TEXT_UNTOUCHED: $html = trim($field); break; 683 case CONVERT_LINEBREAKS: $html = nl2br(trim($field)); break; 684 case USE_TEXTILE: 685 $html = $textile->TextileThis($field); 686 break; 687 } 688 return $html; 689 } 690 691 } 692 693 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Feb 18 03:42:45 2008 | Cross-referenced by PHPXref 0.7 |