[ Index ] [ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]

PHP Cross Reference of TXP stable 4.0.6

title

Body

[close]

/textpattern/lib/ -> txplib_wrapper.php (source)

   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  ?>


Generated: Mon Feb 18 03:42:45 2008 Cross-referenced by PHPXref 0.7