Source for file abook_database.php

Documentation is available at abook_database.php

  1. <?php
  2.  
  3. /**
  4.  * abook_database.php
  5.  *
  6.  * Supported database schema
  7.  * <pre>
  8.  *  owner varchar(128) NOT NULL
  9.  *  nickname varchar(16) NOT NULL
  10.  *  firstname varchar(128)
  11.  *  lastname varchar(128)
  12.  *  email varchar(128) NOT NULL
  13.  *  label varchar(255)
  14.  *  PRIMARY KEY (owner,nickname)
  15.  * </pre>
  16.  *
  17.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  18.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  19.  * @version $Id: abook_database.php,v 1.44 2006/07/15 12:00:44 tokul Exp $
  20.  * @package squirrelmail
  21.  * @subpackage addressbook
  22.  */
  23.  
  24. /**
  25.  * Needs the DB functions
  26.  * Don't display errors here. Error will be set in class constructor function.
  27.  */
  28. @include_once('DB.php');
  29.  
  30. /**
  31.  * Address book in a database backend
  32.  *
  33.  * Backend for personal/shared address book stored in a database,
  34.  * accessed using the DB-classes in PEAR.
  35.  *
  36.  * IMPORTANT:  The PEAR modules must be in the include path
  37.  * for this class to work.
  38.  *
  39.  * An array with the following elements must be passed to
  40.  * the class constructor (elements marked ? are optional):
  41.  * <pre>
  42.  *   dsn       => database DNS (see PEAR for syntax)
  43.  *   table     => table to store addresses in (must exist)
  44.  *   owner     => current user (owner of address data)
  45.  * ? name      => name of address book
  46.  * ? writeable => set writeable flag (true/false)
  47.  * ? listing   => enable/disable listing
  48.  * </pre>
  49.  * The table used should have the following columns:
  50.  * owner, nickname, firstname, lastname, email, label
  51.  * The pair (owner,nickname) should be unique (primary key).
  52.  *
  53.  *  NOTE. This class should not be used directly. Use the
  54.  *        "AddressBook" class instead.
  55.  * @package squirrelmail
  56.  * @subpackage addressbook
  57.  */
  58.     /**
  59.      * Backend type
  60.      * @var string 
  61.      */
  62.     var $btype = 'local';
  63.     /**
  64.      * Backend name
  65.      * @var string 
  66.      */
  67.     var $bname = 'database';
  68.  
  69.     /**
  70.      * Data Source Name (connection description)
  71.      * @var string 
  72.      */
  73.     var $dsn       = '';
  74.     /**
  75.      * Table that stores addresses
  76.      * @var string 
  77.      */
  78.     var $table     = '';
  79.     /**
  80.      * Owner name
  81.      *
  82.      * Limits list of database entries visible to end user
  83.      * @var string 
  84.      */
  85.     var $owner     = '';
  86.     /**
  87.      * Database Handle
  88.      * @var resource 
  89.      */
  90.     var $dbh       = false;
  91.     /**
  92.      * Enable/disable writing into address book
  93.      * @var bool 
  94.      */
  95.     var $writeable = true;
  96.     /**
  97.      * Enable/disable address book listing
  98.      * @var bool 
  99.      */
  100.     var $listing = true;
  101.  
  102.     /* ========================== Private ======================= */
  103.  
  104.     /**
  105.      * Constructor
  106.      * @param array $param address book backend options
  107.      */
  108.     function abook_database($param{
  109.         $this->sname = _("Personal address book");
  110.  
  111.         /* test if Pear DB class is available and freak out if it is not */
  112.         if (class_exists('DB')) {
  113.             // same error also in db_prefs.php
  114.             $error  _("Could not include PEAR database functions required for the database backend.""\n";
  115.             $error .= sprintf(_("Is PEAR installed, and is the include path set correctly to find %s?"),
  116.                               'DB.php'"\n";
  117.             $error .= _("Please contact your system administrator and report this error.");
  118.             return $this->set_error($error);
  119.         }
  120.  
  121.         if (is_array($param)) {
  122.             if (empty($param['dsn']||
  123.                 empty($param['table']||
  124.                 empty($param['owner'])) {
  125.                 return $this->set_error('Invalid parameters');
  126.             }
  127.  
  128.             $this->dsn   = $param['dsn'];
  129.             $this->table = $param['table'];
  130.             $this->owner = $param['owner'];
  131.  
  132.             if (!empty($param['name'])) {
  133.                $this->sname = $param['name'];
  134.             }
  135.  
  136.             if (isset($param['writeable'])) {
  137.                $this->writeable = $param['writeable'];
  138.             }
  139.  
  140.             if (isset($param['listing'])) {
  141.                $this->listing = $param['listing'];
  142.             }
  143.  
  144.             $this->open(true);
  145.         }
  146.         else {
  147.             return $this->set_error('Invalid argument to constructor');
  148.         }
  149.     }
  150.  
  151.  
  152.     /**
  153.      * Open the database.
  154.      * @param bool $new new connection if it is true
  155.      * @return bool 
  156.      */
  157.     function open($new false{
  158.         $this->error = '';
  159.  
  160.         /* Return true is file is open and $new is unset */
  161.         if ($this->dbh && !$new{
  162.             return true;
  163.         }
  164.  
  165.         /* Close old file, if any */
  166.         if ($this->dbh{
  167.             $this->close();
  168.         }
  169.  
  170.         $dbh DB::connect($this->dsntrue);
  171.  
  172.         if (DB::isError($dbh)) {
  173.             return $this->set_error(sprintf(_("Database error: %s"),
  174.                                             DB::errorMessage($dbh)));
  175.         }
  176.  
  177.         $this->dbh = $dbh;
  178.  
  179.         /**
  180.          * field names are lowercased.
  181.          * We use unquoted identifiers and they use upper case in Oracle
  182.          */
  183.         $this->dbh->setOption('portability'DB_PORTABILITY_LOWERCASE);
  184.  
  185.         return true;
  186.     }
  187.  
  188.     /**
  189.      * Close the file and forget the filehandle
  190.      */
  191.     function close({
  192.         $this->dbh->disconnect();
  193.         $this->dbh = false;
  194.     }
  195.  
  196.     /* ========================== Public ======================== */
  197.  
  198.     /**
  199.      * Search the database
  200.      *
  201.      * Backend supports only * and ? wildcards. Complex eregs are not supported.
  202.      * Search is case insensitive.
  203.      * @param string $expr search expression
  204.      * @return array search results. boolean false on error
  205.      */
  206.     function search($expr{
  207.         $ret array();
  208.         if(!$this->open()) {
  209.             return false;
  210.         }
  211.  
  212.         /* To be replaced by advanded search expression parsing */
  213.         if (is_array($expr)) {
  214.             return;
  215.         }
  216.  
  217.         // don't allow wide search when listing is disabled.
  218.         if ($expr=='*' && $this->listing)
  219.             return array();
  220.  
  221.         /* lowercase expression in order to make it case insensitive */
  222.         $expr strtolower($expr);
  223.  
  224.         /* escape SQL wildcards */
  225.         $expr str_replace('_''\\_'$expr);
  226.         $expr str_replace('%''\\%'$expr);
  227.  
  228.         /* Convert wildcards to SQL syntax  */
  229.         $expr str_replace('?''_'$expr);
  230.         $expr str_replace('*''%'$expr);
  231.         $expr $this->dbh->quoteString($expr);
  232.         $expr "%$expr%";
  233.  
  234.         /* create escape expression */
  235.         $escape 'ESCAPE \'' $this->dbh->quoteString('\\''\'';
  236.     
  237.         $query sprintf("SELECT * FROM %s WHERE owner='%s' AND " .
  238.                          "(LOWER(firstname) LIKE '%s' %s OR LOWER(lastname) LIKE '%s' %s)",
  239.                          $this->table$this->owner$expr$escape$expr$escape);
  240.  
  241.         $res $this->dbh->query($query);
  242.  
  243.         if (DB::isError($res)) {
  244.             return $this->set_error(sprintf(_("Database error: %s"),
  245.                                             DB::errorMessage($res)));
  246.         }
  247.  
  248.         while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  249.             array_push($retarray('nickname'  => $row['nickname'],
  250.                                    'name'      => $this->fullname($row['firstname']$row['lastname']),
  251.                                    'firstname' => $row['firstname'],
  252.                                    'lastname'  => $row['lastname'],
  253.                                    'email'     => $row['email'],
  254.                                    'label'     => $row['label'],
  255.                                    'backend'   => $this->bnum,
  256.                                    'source'    => &$this->sname));
  257.         }
  258.         return $ret;
  259.     }
  260.  
  261.     /**
  262.      * Lookup alias
  263.      * @param string $alias alias
  264.      * @return array search results
  265.      */
  266.     function lookup($alias{
  267.         if (empty($alias)) {
  268.             return array();
  269.         }
  270.  
  271.         $alias strtolower($alias);
  272.  
  273.         if (!$this->open()) {
  274.             return false;
  275.         }
  276.  
  277.         $query sprintf("SELECT * FROM %s WHERE owner='%s' AND LOWER(nickname)='%s'",
  278.                          $this->table$this->owner$this->dbh->quoteString($alias));
  279.  
  280.         $res $this->dbh->query($query);
  281.  
  282.         if (DB::isError($res)) {
  283.             return $this->set_error(sprintf(_("Database error: %s"),
  284.                                             DB::errorMessage($res)));
  285.         }
  286.  
  287.         if ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  288.             return array('nickname'  => $row['nickname'],
  289.                          'name'      => $this->fullname($row['firstname']$row['lastname']),
  290.                          'firstname' => $row['firstname'],
  291.                          'lastname'  => $row['lastname'],
  292.                          'email'     => $row['email'],
  293.                          'label'     => $row['label'],
  294.                          'backend'   => $this->bnum,
  295.                          'source'    => &$this->sname);
  296.         }
  297.         return array();
  298.     }
  299.  
  300.     /**
  301.      * List all addresses
  302.      * @return array search results
  303.      */
  304.     function list_addr({
  305.         $ret array();
  306.         if (!$this->open()) {
  307.             return false;
  308.         }
  309.  
  310.         if(isset($this->listing&& !$this->listing{
  311.             return array();
  312.         }
  313.  
  314.  
  315.         $query sprintf("SELECT * FROM %s WHERE owner='%s'",
  316.                          $this->table$this->owner);
  317.  
  318.         $res $this->dbh->query($query);
  319.  
  320.         if (DB::isError($res)) {
  321.             return $this->set_error(sprintf(_("Database error: %s"),
  322.                                             DB::errorMessage($res)));
  323.         }
  324.  
  325.         while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  326.             array_push($retarray('nickname'  => $row['nickname'],
  327.                                    'name'      => $this->fullname($row['firstname']$row['lastname']),
  328.                                    'firstname' => $row['firstname'],
  329.                                    'lastname'  => $row['lastname'],
  330.                                    'email'     => $row['email'],
  331.                                    'label'     => $row['label'],
  332.                                    'backend'   => $this->bnum,
  333.                                    'source'    => &$this->sname));
  334.         }
  335.         return $ret;
  336.     }
  337.  
  338.     /**
  339.      * Add address
  340.      * @param array $userdata added data
  341.      * @return bool 
  342.      */
  343.     function add($userdata{
  344.         if (!$this->writeable{
  345.             return $this->set_error(_("Address book is read-only"));
  346.         }
  347.  
  348.         if (!$this->open()) {
  349.             return false;
  350.         }
  351.  
  352.         /* See if user exist already */
  353.         $ret $this->lookup($userdata['nickname']);
  354.         if (!empty($ret)) {
  355.             return $this->set_error(sprintf(_("User \"%s\" already exists"),$ret['nickname']));
  356.         }
  357.  
  358.         /* Create query */
  359.         $query sprintf("INSERT INTO %s (owner, nickname, firstname, " .
  360.                          "lastname, email, label) VALUES('%s','%s','%s'," .
  361.                          "'%s','%s','%s')",
  362.                          $this->table$this->owner,
  363.                          $this->dbh->quoteString($userdata['nickname']),
  364.                          $this->dbh->quoteString($userdata['firstname']),
  365.                          $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  366.                          $this->dbh->quoteString($userdata['email']),
  367.                          $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')) );
  368.  
  369.          /* Do the insert */
  370.          $r $this->dbh->simpleQuery($query);
  371.  
  372.          /* Check for errors */
  373.          if (DB::isError($r)) {
  374.              return $this->set_error(sprintf(_("Database error: %s"),
  375.                                              DB::errorMessage($r)));
  376.          }
  377.          return true;
  378.     }
  379.  
  380.     /**
  381.      * Deletes address book entries
  382.      * @param array $alias aliases that have to be deleted. numerical
  383.      *   array with nickname values
  384.      * @return bool 
  385.      */
  386.     function remove($alias{
  387.         if (!$this->writeable{
  388.             return $this->set_error(_("Address book is read-only"));
  389.         }
  390.  
  391.         if (!$this->open()) {
  392.             return false;
  393.         }
  394.  
  395.         /* Create query */
  396.         $query sprintf("DELETE FROM %s WHERE owner='%s' AND (",
  397.                          $this->table$this->owner);
  398.  
  399.         $sepstr '';
  400.         while (list($undef$nicknameeach($alias)) {
  401.             $query .= sprintf("%s nickname='%s' "$sepstr,
  402.                               $this->dbh->quoteString($nickname));
  403.             $sepstr 'OR';
  404.         }
  405.         $query .= ')';
  406.  
  407.         /* Delete entry */
  408.         $r $this->dbh->simpleQuery($query);
  409.  
  410.         /* Check for errors */
  411.         if (DB::isError($r)) {
  412.             return $this->set_error(sprintf(_("Database error: %s"),
  413.                                             DB::errorMessage($r)));
  414.         }
  415.         return true;
  416.     }
  417.  
  418.     /**
  419.      * Modify address
  420.      * @param string $alias modified alias
  421.      * @param array $userdata new data
  422.      * @return bool 
  423.      */
  424.     function modify($alias$userdata{
  425.         if (!$this->writeable{
  426.             return $this->set_error(_("Address book is read-only"));
  427.         }
  428.  
  429.         if (!$this->open()) {
  430.             return false;
  431.         }
  432.  
  433.          /* See if user exist */
  434.         $ret $this->lookup($alias);
  435.         if (empty($ret)) {
  436.             return $this->set_error(sprintf(_("User \"%s\" does not exist"),$alias));
  437.         }
  438.  
  439.         /* make sure that new nickname is not used */
  440.         if (strtolower($alias!= strtolower($userdata['nickname'])) {
  441.             /* same check as in add() */
  442.             $ret $this->lookup($userdata['nickname']);
  443.             if (!empty($ret)) {
  444.                 $error sprintf(_("User '%s' already exist.")$ret['nickname']);
  445.                 return $this->set_error($error);
  446.             }
  447.         }
  448.  
  449.         /* Create query */
  450.         $query sprintf("UPDATE %s SET nickname='%s', firstname='%s', ".
  451.                          "lastname='%s', email='%s', label='%s' ".
  452.                          "WHERE owner='%s' AND nickname='%s'",
  453.                          $this->table,
  454.                          $this->dbh->quoteString($userdata['nickname']),
  455.                          $this->dbh->quoteString($userdata['firstname']),
  456.                          $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  457.                          $this->dbh->quoteString($userdata['email']),
  458.                          $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')),
  459.                          $this->owner,
  460.                          $this->dbh->quoteString($alias) );
  461.  
  462.         /* Do the insert */
  463.         $r $this->dbh->simpleQuery($query);
  464.  
  465.         /* Check for errors */
  466.         if (DB::isError($r)) {
  467.             return $this->set_error(sprintf(_("Database error: %s"),
  468.                                             DB::errorMessage($r)));
  469.         }
  470.         return true;
  471.     }
  472. /* End of class abook_database */
  473.  
  474. // vim: et ts=4

Documentation generated on Sat, 07 Oct 2006 16:08:24 +0300 by phpDocumentor 1.3.0RC6