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 1999-2020 The SquirrelMail Project Team
  18.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  19.  * @version $Id: abook_database.php 14845 2020-01-07 08:09:34Z pdontthink $
  20.  * @package squirrelmail
  21.  * @subpackage addressbook
  22.  */
  23.  
  24. /**
  25.  * Needs either PDO or the DB functions
  26.  * Don't display errors here. Error will be set in class constructor function.
  27.  */
  28. global $use_pdo$disable_pdo;
  29. if (empty($disable_pdo&& class_exists('PDO'))
  30.     $use_pdo TRUE;
  31. else
  32.     $use_pdo FALSE;
  33.  
  34. if (!$use_pdo)
  35.     @include_once('DB.php');
  36.  
  37. /**
  38.  * Address book in a database backend
  39.  *
  40.  * Backend for personal/shared address book stored in a database,
  41.  * accessed using the DB-classes in PEAR or PDO, the latter taking
  42.  * precedence if available..
  43.  *
  44.  * IMPORTANT:  If PDO is not available (it should be installed by
  45.  *             default since PHP 5.1), then the PEAR modules must
  46.  *             be in the include path for this class to work.
  47.  *
  48.  * An array with the following elements must be passed to
  49.  * the class constructor (elements marked ? are optional):
  50.  * <pre>
  51.  *   dsn       => database DNS (see PEAR for syntax, but more or
  52.  *                less it is:  mysql://user:pass@hostname/dbname)
  53.  *   table     => table to store addresses in (must exist)
  54.  *   owner     => current user (owner of address data)
  55.  * ? name      => name of address book
  56.  * ? writeable => set writeable flag (true/false)
  57.  * ? listing   => enable/disable listing
  58.  * </pre>
  59.  * The table used should have the following columns:
  60.  * owner, nickname, firstname, lastname, email, label
  61.  * The pair (owner,nickname) should be unique (primary key).
  62.  *
  63.  *  NOTE. This class should not be used directly. Use the
  64.  *        "AddressBook" class instead.
  65.  *
  66.  * Three settings that control PDO behavior can be specified in
  67.  * config/config_local.php if needed:
  68.  *    boolean $disable_pdo SquirrelMail uses PDO by default to access the
  69.  *                         user preferences and address book databases, but
  70.  *                         setting this to TRUE will cause SquirrelMail to
  71.  *                         fall back to using Pear DB instead.
  72.  *    boolean $pdo_show_sql_errors When database errors are encountered,
  73.  *                                 setting this to TRUE causes the actual
  74.  *                                 database error to be displayed, otherwise
  75.  *                                 generic errors are displayed, preventing
  76.  *                                 internal database information from being
  77.  *                                 exposed. This should be enabled only for
  78.  *                                 debugging purposes.
  79.  *    string $pdo_identifier_quote_char By default, SquirrelMail will quote
  80.  *                                      table and field names in database
  81.  *                                      queries with what it thinks is the
  82.  *                                      appropriate quote character for the
  83.  *                                      database type being used (backtick
  84.  *                                      for MySQL (and thus MariaDB), double
  85.  *                                      quotes for all others), but you can
  86.  *                                      override the character used by
  87.  *                                      putting it here, or tell SquirrelMail
  88.  *                                      NOT to quote identifiers by setting
  89.  *                                      this to "none"
  90.  *
  91.  * @package squirrelmail
  92.  * @subpackage addressbook
  93.  */
  94.     /**
  95.      * Backend type
  96.      * @var string 
  97.      */
  98.     var $btype = 'local';
  99.     /**
  100.      * Backend name
  101.      * @var string 
  102.      */
  103.     var $bname = 'database';
  104.  
  105.     /**
  106.      * Data Source Name (connection description)
  107.      * @var string 
  108.      */
  109.     var $dsn       = '';
  110.  
  111.     /**
  112.      * Character used to quote database table
  113.      * and field names
  114.      * @var string 
  115.      */
  116.     var $identifier_quote_char = '';
  117.  
  118.     /**
  119.      * Table that stores addresses
  120.      * @var string 
  121.      */
  122.     var $table     = '';
  123.     /**
  124.      * Owner name
  125.      *
  126.      * Limits list of database entries visible to end user
  127.      * @var string 
  128.      */
  129.     var $owner     = '';
  130.     /**
  131.      * Database Handle
  132.      * @var resource 
  133.      */
  134.     var $dbh       = false;
  135.     /**
  136.      * Enable/disable writing into address book
  137.      * @var bool 
  138.      */
  139.     var $writeable = true;
  140.     /**
  141.      * Enable/disable address book listing
  142.      * @var bool 
  143.      */
  144.     var $listing = true;
  145.  
  146.     /* ========================== Private ======================= */
  147.  
  148.     /**
  149.      * Constructor (PHP5 style, required in some future version of PHP)
  150.      * @param array $param address book backend options
  151.      */
  152.     function __construct($param{
  153.         $this->sname = _("Personal Address Book");
  154.  
  155.         /* test if PDO or Pear DB classes are available and freak out if necessary */
  156.         global $use_pdo;
  157.         if (!$use_pdo && !class_exists('DB')) {
  158.             // same error also in db_prefs.php
  159.             $error  _("Could not find or include PHP PDO or PEAR database functions required for the database backend.""\n";
  160.             $error .= sprintf(_("PDO should come preinstalled with PHP version 5.1 or higher. Otherwise, is PEAR installed, and is the include path set correctly to find %s?")'DB.php'"\n";
  161.             $error .= _("Please contact your system administrator and report this error.");
  162.             return $this->set_error($error);
  163.         }
  164.  
  165.         if (is_array($param)) {
  166.             if (empty($param['dsn']||
  167.                 empty($param['table']||
  168.                 empty($param['owner'])) {
  169.                 return $this->set_error('Invalid parameters');
  170.             }
  171.  
  172.             $this->dsn   = $param['dsn'];
  173.             $this->table = $param['table'];
  174.             $this->owner = $param['owner'];
  175.  
  176.             if (!empty($param['name'])) {
  177.                $this->sname = $param['name'];
  178.             }
  179.  
  180.             if (isset($param['writeable'])) {
  181.                $this->writeable = $param['writeable'];
  182.             }
  183.  
  184.             if (isset($param['listing'])) {
  185.                $this->listing = $param['listing'];
  186.             }
  187.  
  188.             // figure out identifier quoting (only used for PDO, though we could change that)
  189.             global $pdo_identifier_quote_char;
  190.             if (empty($pdo_identifier_quote_char)) {
  191.                 if (strpos($this->dsn'mysql'=== 0)
  192.                     $this->identifier_quote_char = '`';
  193.                 else
  194.                     $this->identifier_quote_char = '"';
  195.             else if ($pdo_identifier_quote_char === 'none')
  196.                 $this->identifier_quote_char = '';
  197.             else
  198.                 $this->identifier_quote_char = $pdo_identifier_quote_char;
  199.  
  200.  
  201.             $this->open(true);
  202.         }
  203.         else {
  204.             return $this->set_error('Invalid argument to constructor');
  205.         }
  206.     }
  207.  
  208.     /**
  209.      * Constructor (PHP4 style, kept for compatibility reasons)
  210.      * @param array $param address book backend options
  211.      */
  212.     function abook_database($param{
  213.         return self::__construct($param);
  214.     }
  215.  
  216.     /**
  217.      * Open the database.
  218.      * @param bool $new new connection if it is true
  219.      * @return bool 
  220.      */
  221.     function open($new false{
  222.         global $use_pdo;
  223.         $this->error = '';
  224.  
  225.         /* Return true is file is open and $new is unset */
  226.         if ($this->dbh && !$new{
  227.             return true;
  228.         }
  229.  
  230.         /* Close old file, if any */
  231.         if ($this->dbh{
  232.             $this->close();
  233.         }
  234.  
  235.         if ($use_pdo{
  236.             // parse and convert DSN to PDO style
  237.             // Pear's full DSN syntax is one of the following:
  238.             //    phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
  239.             //    phptype(syntax)://user:pass@protocol(proto_opts)/database
  240.             //
  241.             // $matches will contain:
  242.             // 1: database type
  243.             // 2: username
  244.             // 3: password
  245.             // 4: hostname (and possible port number) OR protocol (and possible protocol options)
  246.             // 5: database name (and possible options)
  247.             // 6: port number (moved from match number 4)
  248.             // 7: options (moved from match number 5)
  249.             // 8: protocol (instead of hostname)
  250.             // 9: protocol options (moved from match number 4/8)
  251. //TODO: do we care about supporting cases where no password is given? (this is a legal DSN, but causes an error below)
  252.             if (!preg_match('|^(.+)://(.+):(.+)@(.+)/(.+)$|i'$this->dsn$matches)) {
  253.                 return $this->set_error(_("Could not parse prefs DSN"));
  254.             }
  255.             $matches[6NULL;
  256.             $matches[7NULL;
  257.             $matches[8NULL;
  258.             $matches[9NULL;
  259.             if (preg_match('|^(.+):(\d+)$|'$matches[4]$host_port_matches)) {
  260.                 $matches[4$host_port_matches[1];
  261.                 $matches[6$host_port_matches[2];
  262.             }
  263.             if (preg_match('|^(.+?)\((.+)\)$|'$matches[4]$protocol_matches)) {
  264.                 $matches[8$protocol_matches[1];
  265.                 $matches[9$protocol_matches[2];
  266.                 $matches[4NULL;
  267.                 $matches[6NULL;
  268.             }
  269. //TODO: currently we just ignore options specified on the end of the DSN
  270.             if (preg_match('|^(.+?)\?(.+)$|'$matches[5]$database_name_options_matches)) {
  271.                 $matches[5$database_name_options_matches[1];
  272.                 $matches[7$database_name_options_matches[2];
  273.             }
  274.             if ($matches[8=== 'unix' && !empty($matches[9]))
  275.                 $pdo_prefs_dsn $matches[1':unix_socket=' $matches[9';dbname=' $matches[5];
  276.             else
  277.                 $pdo_prefs_dsn $matches[1':host=' $matches[4(!empty($matches[6]';port=' $matches[6''';dbname=' $matches[5];
  278.             try {
  279.                 $dbh new PDO($pdo_prefs_dsn$matches[2]$matches[3]);
  280.             catch (Exception $e{
  281.                 return $this->set_error(sprintf(_("Database error: %s")$e->getMessage()));
  282.             }
  283.  
  284.             $dbh->setAttribute(PDO::ATTR_CASEPDO::CASE_LOWER);
  285.  
  286.         else {
  287.             $dbh DB::connect($this->dsntrue);
  288.  
  289.             if (DB::isError($dbh)) {
  290.                 return $this->set_error(sprintf(_("Database error: %s"),
  291.                                                 DB::errorMessage($dbh)));
  292.             }
  293.  
  294.             /**
  295.              * field names are lowercased.
  296.              * We use unquoted identifiers and they use upper case in Oracle
  297.              */
  298.             $dbh->setOption('portability'DB_PORTABILITY_LOWERCASE);
  299.         }
  300.  
  301.         $this->dbh = $dbh;
  302.         return true;
  303.     }
  304.  
  305.     /**
  306.      * Close the file and forget the filehandle
  307.      */
  308.     function close({
  309.         global $use_pdo;
  310.         if ($use_pdo{
  311.             $this->dbh = NULL;
  312.         else {
  313.             $this->dbh->disconnect();
  314.             $this->dbh = false;
  315.         }
  316.     }
  317.  
  318.     /**
  319.      * Determine internal database field name given one of
  320.      * the SquirrelMail SM_ABOOK_FIELD_* constants
  321.      *
  322.      * @param integer $field The SM_ABOOK_FIELD_* contant to look up
  323.      *
  324.      * @return string The desired field name, or the string "ERROR"
  325.      *                 if the $field is not understood (the caller
  326.      *                 is responsible for handing errors)
  327.      *
  328.      */
  329.     function get_field_name($field{
  330.         switch ($field{
  331.             case SM_ABOOK_FIELD_NICKNAME:
  332.                 return 'nickname';
  333.             case SM_ABOOK_FIELD_FIRSTNAME:
  334.                 return 'firstname';
  335.             case SM_ABOOK_FIELD_LASTNAME:
  336.                 return 'lastname';
  337.             case SM_ABOOK_FIELD_EMAIL:
  338.                 return 'email';
  339.             case SM_ABOOK_FIELD_LABEL:
  340.                 return 'label';
  341.             default:
  342.                 return 'ERROR';
  343.         }
  344.     }
  345.  
  346.     /* ========================== Public ======================== */
  347.  
  348.     /**
  349.      * Search the database
  350.      *
  351.      * Backend supports only * and ? wildcards. Complex eregs are not supported.
  352.      * Search is case insensitive.
  353.      * @param string $expr search expression
  354.      * @return array search results. boolean false on error
  355.      */
  356.     function search($expr{
  357.         $ret array();
  358.         if(!$this->open()) {
  359.             return false;
  360.         }
  361.  
  362.         /* To be replaced by advanded search expression parsing */
  363.         if (is_array($expr)) {
  364.             return;
  365.         }
  366.  
  367.         // don't allow wide search when listing is disabled.
  368.         if ($expr=='*' && $this->listing)
  369.             return array();
  370.  
  371.         /* lowercase expression in order to make it case insensitive */
  372.         $expr strtolower($expr);
  373.  
  374.         /* escape SQL wildcards */
  375.         $expr str_replace('_''\\_'$expr);
  376.         $expr str_replace('%''\\%'$expr);
  377.  
  378.         /* Convert wildcards to SQL syntax  */
  379.         $expr str_replace('?''_'$expr);
  380.         $expr str_replace('*''%'$expr);
  381.  
  382.         $expr "%$expr%";
  383.  
  384.         global $use_pdo$pdo_show_sql_errors;
  385.         if ($use_pdo{
  386.             if (!($sth $this->dbh->prepare('SELECT * FROM ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ' = ? AND (LOWER(' $this->identifier_quote_char . 'firstname' $this->identifier_quote_char . ') LIKE ? ESCAPE ? OR LOWER(' $this->identifier_quote_char . 'lastname' $this->identifier_quote_char . ') LIKE ? ESCAPE ? OR LOWER(' $this->identifier_quote_char . 'email' $this->identifier_quote_char . ') LIKE ? ESCAPE ? OR LOWER(' $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ') LIKE ? ESCAPE ?)'))) {
  387.                 if ($pdo_show_sql_errors)
  388.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  389.                 else
  390.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  391.             }
  392.             if (!($res $sth->execute(array($this->owner$expr'\\'$expr'\\'$expr'\\'$expr'\\')))) {
  393.                 if ($pdo_show_sql_errors)
  394.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  395.                 else
  396.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  397.             }
  398.  
  399.             while ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  400.                 array_push($retarray('nickname'  => $row['nickname'],
  401.                                        'name'      => $this->fullname($row['firstname']$row['lastname']),
  402.                                        'firstname' => $row['firstname'],
  403.                                        'lastname'  => $row['lastname'],
  404.                                        'email'     => $row['email'],
  405.                                        'label'     => $row['label'],
  406.                                        'backend'   => $this->bnum,
  407.                                        'source'    => &$this->sname));
  408.             }
  409.  
  410.         else {
  411.             $expr $this->dbh->quoteString($expr);
  412.  
  413.             /* create escape expression */
  414.             $escape 'ESCAPE \'' $this->dbh->quoteString('\\''\'';
  415.  
  416.             $query sprintf("SELECT * FROM %s WHERE owner='%s' AND " .
  417.                              "(LOWER(firstname) LIKE '%s' %s " .
  418.                              "OR LOWER(lastname) LIKE '%s' %s " .
  419.                              "OR LOWER(email) LIKE '%s' %s " .
  420.                              "OR LOWER(nickname) LIKE '%s' %s)",
  421.                              $this->table$this->owner$expr$escape$expr$escape,
  422.                                                          $expr$escape$expr$escape);
  423.             $res $this->dbh->query($query);
  424.  
  425.             if (DB::isError($res)) {
  426.                 return $this->set_error(sprintf(_("Database error: %s"),
  427.                                                 DB::errorMessage($res)));
  428.             }
  429.  
  430.             while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  431.                 array_push($retarray('nickname'  => $row['nickname'],
  432.                                        'name'      => $this->fullname($row['firstname']$row['lastname']),
  433.                                        'firstname' => $row['firstname'],
  434.                                        'lastname'  => $row['lastname'],
  435.                                        'email'     => $row['email'],
  436.                                        'label'     => $row['label'],
  437.                                        'backend'   => $this->bnum,
  438.                                        'source'    => &$this->sname));
  439.             }
  440.         }
  441.         return $ret;
  442.     }
  443.  
  444.     /**
  445.      * Lookup an address by the indicated field.
  446.      *
  447.      * @param string  $value The value to look up
  448.      * @param integer $field The field to look in, should be one
  449.      *                        of the SM_ABOOK_FIELD_* constants
  450.      *                        defined in include/constants.php
  451.      *                        (OPTIONAL; defaults to nickname field)
  452.      *                        NOTE: uniqueness is only guaranteed
  453.      *                        when the nickname field is used here;
  454.      *                        otherwise, the first matching address
  455.      *                        is returned.
  456.      *
  457.      * @return array Array with lookup results when the value
  458.      *                was found, an empty array if the value was
  459.      *                not found.
  460.      *
  461.      */
  462.     function lookup($value$field=SM_ABOOK_FIELD_NICKNAME{
  463.         if (empty($value)) {
  464.             return array();
  465.         }
  466.  
  467.         $value strtolower($value);
  468.  
  469.         if (!$this->open()) {
  470.             return false;
  471.         }
  472.  
  473.         $db_field $this->get_field_name($field);
  474.         if ($db_field == 'ERROR'{
  475.             return $this->set_error(sprintf(_("Unknown field name: %s")$field));
  476.         }
  477.  
  478.         global $use_pdo$pdo_show_sql_errors;
  479.         if ($use_pdo{
  480.             if (!($sth $this->dbh->prepare('SELECT * FROM ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ' = ? AND LOWER(' $this->identifier_quote_char . $db_field $this->identifier_quote_char . ') = ?'))) {
  481.                 if ($pdo_show_sql_errors)
  482.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  483.                 else
  484.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  485.             }
  486.             if (!($res $sth->execute(array($this->owner$value)))) {
  487.                 if ($pdo_show_sql_errors)
  488.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  489.                 else
  490.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  491.             }
  492.  
  493.             if ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  494.                 return array('nickname'  => $row['nickname'],
  495.                              'name'      => $this->fullname($row['firstname']$row['lastname']),
  496.                              'firstname' => $row['firstname'],
  497.                              'lastname'  => $row['lastname'],
  498.                              'email'     => $row['email'],
  499.                              'label'     => $row['label'],
  500.                              'backend'   => $this->bnum,
  501.                              'source'    => &$this->sname);
  502.             }
  503.  
  504.         else {
  505.             $query sprintf("SELECT * FROM %s WHERE owner = '%s' AND LOWER(%s) = '%s'",
  506.                              $this->table$this->owner$db_field
  507.                              $this->dbh->quoteString($value));
  508.  
  509.             $res $this->dbh->query($query);
  510.  
  511.             if (DB::isError($res)) {
  512.                 return $this->set_error(sprintf(_("Database error: %s"),
  513.                                                 DB::errorMessage($res)));
  514.             }
  515.  
  516.             if ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  517.                 return array('nickname'  => $row['nickname'],
  518.                              'name'      => $this->fullname($row['firstname']$row['lastname']),
  519.                              'firstname' => $row['firstname'],
  520.                              'lastname'  => $row['lastname'],
  521.                              'email'     => $row['email'],
  522.                              'label'     => $row['label'],
  523.                              'backend'   => $this->bnum,
  524.                              'source'    => &$this->sname);
  525.             }
  526.         }
  527.  
  528.         return array();
  529.     }
  530.  
  531.     /**
  532.      * List all addresses
  533.      * @return array search results
  534.      */
  535.     function list_addr({
  536.         $ret array();
  537.         if (!$this->open()) {
  538.             return false;
  539.         }
  540.  
  541.         if(isset($this->listing&& !$this->listing{
  542.             return array();
  543.         }
  544.  
  545.  
  546.         global $use_pdo$pdo_show_sql_errors;
  547.         if ($use_pdo{
  548.             if (!($sth $this->dbh->prepare('SELECT * FROM ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ' = ?'))) {
  549.                 if ($pdo_show_sql_errors)
  550.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  551.                 else
  552.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  553.             }
  554.             if (!($res $sth->execute(array($this->owner)))) {
  555.                 if ($pdo_show_sql_errors)
  556.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  557.                 else
  558.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  559.             }
  560.  
  561.             while ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  562.                 array_push($retarray('nickname'  => $row['nickname'],
  563.                                        'name'      => $this->fullname($row['firstname']$row['lastname']),
  564.                                        'firstname' => $row['firstname'],
  565.                                        'lastname'  => $row['lastname'],
  566.                                        'email'     => $row['email'],
  567.                                        'label'     => $row['label'],
  568.                                        'backend'   => $this->bnum,
  569.                                        'source'    => &$this->sname));
  570.             }
  571.         else {
  572.             $query sprintf("SELECT * FROM %s WHERE owner='%s'",
  573.                              $this->table$this->owner);
  574.  
  575.             $res $this->dbh->query($query);
  576.  
  577.             if (DB::isError($res)) {
  578.                 return $this->set_error(sprintf(_("Database error: %s"),
  579.                                                 DB::errorMessage($res)));
  580.             }
  581.  
  582.             while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  583.                 array_push($retarray('nickname'  => $row['nickname'],
  584.                                        'name'      => $this->fullname($row['firstname']$row['lastname']),
  585.                                        'firstname' => $row['firstname'],
  586.                                        'lastname'  => $row['lastname'],
  587.                                        'email'     => $row['email'],
  588.                                        'label'     => $row['label'],
  589.                                        'backend'   => $this->bnum,
  590.                                        'source'    => &$this->sname));
  591.             }
  592.         }
  593.  
  594.         return $ret;
  595.     }
  596.  
  597.     /**
  598.      * Add address
  599.      * @param array $userdata added data
  600.      * @return bool 
  601.      */
  602.     function add($userdata{
  603.         if (!$this->writeable{
  604.             return $this->set_error(_("Address book is read-only"));
  605.         }
  606.  
  607.         if (!$this->open()) {
  608.             return false;
  609.         }
  610.  
  611.         // NB: if you want to check for some unwanted characters
  612.         //     or other problems, do so here like this:
  613.         // TODO: Should pull all validation code out into a separate function
  614.         //if (strpos($userdata['nickname'], ' ')) {
  615.         //    return $this->set_error(_("Nickname contains illegal characters"));
  616.         //}
  617.  
  618.         /* See if user exist already */
  619.         $ret $this->lookup($userdata['nickname']);
  620.         if (!empty($ret)) {
  621.             return $this->set_error(sprintf(_("User \"%s\" already exists")$ret['nickname']));
  622.         }
  623.  
  624.         global $use_pdo$pdo_show_sql_errors;
  625.         if ($use_pdo{
  626.             if (!($sth $this->dbh->prepare('INSERT INTO ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' (' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ', ' $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ', ' $this->identifier_quote_char . 'firstname' $this->identifier_quote_char . ', ' $this->identifier_quote_char . 'lastname' $this->identifier_quote_char . ', ' $this->identifier_quote_char . 'email' $this->identifier_quote_char . ', ' $this->identifier_quote_char . 'label' $this->identifier_quote_char . ') VALUES (?, ?, ?, ?, ?, ?)'))) {
  627.                 if ($pdo_show_sql_errors)
  628.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  629.                 else
  630.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  631.             }
  632.             if (!($res $sth->execute(array($this->owner$userdata['nickname']$userdata['firstname'](!empty($userdata['lastname']$userdata['lastname''')$userdata['email'](!empty($userdata['label']$userdata['label'''))))) {
  633.                 if ($pdo_show_sql_errors)
  634.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  635.                 else
  636.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  637.             }
  638.         else {
  639.             /* Create query */
  640.             $query sprintf("INSERT INTO %s (owner, nickname, firstname, " .
  641.                              "lastname, email, label) VALUES('%s','%s','%s'," .
  642.                              "'%s','%s','%s')",
  643.                              $this->table$this->owner,
  644.                              $this->dbh->quoteString($userdata['nickname']),
  645.                              $this->dbh->quoteString($userdata['firstname']),
  646.                              $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  647.                              $this->dbh->quoteString($userdata['email']),
  648.                              $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')) );
  649.  
  650.             /* Do the insert */
  651.             $r $this->dbh->simpleQuery($query);
  652.  
  653.             /* Check for errors */
  654.             if (DB::isError($r)) {
  655.                 return $this->set_error(sprintf(_("Database error: %s"),
  656.                                                 DB::errorMessage($r)));
  657.             }
  658.         }
  659.  
  660.          return true;
  661.     }
  662.  
  663.     /**
  664.      * Deletes address book entries
  665.      * @param array $alias aliases that have to be deleted. numerical
  666.      *   array with nickname values
  667.      * @return bool 
  668.      */
  669.     function remove($alias{
  670.         if (!$this->writeable{
  671.             return $this->set_error(_("Address book is read-only"));
  672.         }
  673.  
  674.         if (!$this->open()) {
  675.             return false;
  676.         }
  677.  
  678.         global $use_pdo$pdo_show_sql_errors;
  679.         if ($use_pdo{
  680.             $sepstr '';
  681.             $where_clause '';
  682.             $where_clause_args array();
  683.             while (list($undef$nicknameeach($alias)) {
  684.                 $where_clause .= $sepstr $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ' = ?';
  685.                 $where_clause_args[$nickname;
  686.                 $sepstr ' OR ';
  687.             }
  688.             if (!($sth $this->dbh->prepare('DELETE FROM ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ' = ? AND (' $where_clause ')'))) {
  689.                 if ($pdo_show_sql_errors)
  690.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  691.                 else
  692.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  693.             }
  694.             array_unshift($where_clause_args$this->owner);
  695.             if (!($res $sth->execute($where_clause_args))) {
  696.                 if ($pdo_show_sql_errors)
  697.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  698.                 else
  699.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  700.             }
  701.         else {
  702.             /* Create query */
  703.             $query sprintf("DELETE FROM %s WHERE owner='%s' AND (",
  704.                              $this->table$this->owner);
  705.  
  706.             $sepstr '';
  707.             while (list($undef$nicknameeach($alias)) {
  708.                 $query .= sprintf("%s nickname='%s' "$sepstr,
  709.                                   $this->dbh->quoteString($nickname));
  710.                 $sepstr 'OR';
  711.             }
  712.             $query .= ')';
  713.  
  714.             /* Delete entry */
  715.             $r $this->dbh->simpleQuery($query);
  716.  
  717.             /* Check for errors */
  718.             if (DB::isError($r)) {
  719.                 return $this->set_error(sprintf(_("Database error: %s"),
  720.                                                 DB::errorMessage($r)));
  721.             }
  722.         }
  723.  
  724.         return true;
  725.     }
  726.  
  727.     /**
  728.      * Modify address
  729.      * @param string $alias modified alias
  730.      * @param array $userdata new data
  731.      * @return bool 
  732.      */
  733.     function modify($alias$userdata{
  734.         if (!$this->writeable{
  735.             return $this->set_error(_("Address book is read-only"));
  736.         }
  737.  
  738.         if (!$this->open()) {
  739.             return false;
  740.         }
  741.  
  742.         // NB: if you want to check for some unwanted characters
  743.         //     or other problems, do so here like this:
  744.         // TODO: Should pull all validation code out into a separate function
  745.         //if (strpos($userdata['nickname'], ' ')) {
  746.         //    return $this->set_error(_("Nickname contains illegal characters"));
  747.         //}
  748.  
  749.          /* See if user exist */
  750.         $ret $this->lookup($alias);
  751.         if (empty($ret)) {
  752.             return $this->set_error(sprintf(_("User \"%s\" does not exist"),$alias));
  753.         }
  754.  
  755.         /* make sure that new nickname is not used */
  756.         if (strtolower($alias!= strtolower($userdata['nickname'])) {
  757.             /* same check as in add() */
  758.             $ret $this->lookup($userdata['nickname']);
  759.             if (!empty($ret)) {
  760.                 $error sprintf(_("User '%s' already exist.")$ret['nickname']);
  761.                 return $this->set_error($error);
  762.             }
  763.         }
  764.  
  765.         global $use_pdo$pdo_show_sql_errors;
  766.         if ($use_pdo{
  767.             if (!($sth $this->dbh->prepare('UPDATE ' $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' SET ' $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ' = ?, ' $this->identifier_quote_char . 'firstname' $this->identifier_quote_char . ' = ?, ' $this->identifier_quote_char . 'lastname' $this->identifier_quote_char . ' = ?, ' $this->identifier_quote_char . 'email' $this->identifier_quote_char . ' = ?, ' $this->identifier_quote_char . 'label' $this->identifier_quote_char . ' = ? WHERE ' $this->identifier_quote_char . 'owner' $this->identifier_quote_char . ' = ? AND ' $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ' = ?'))) {
  768.                 if ($pdo_show_sql_errors)
  769.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  770.                 else
  771.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  772.             }
  773.             if (!($res $sth->execute(array($userdata['nickname']$userdata['firstname'](!empty($userdata['lastname']$userdata['lastname''')$userdata['email'](!empty($userdata['label']$userdata['label''')$this->owner$alias)))) {
  774.                 if ($pdo_show_sql_errors)
  775.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  776.                 else
  777.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  778.             }
  779.         else {
  780.             /* Create query */
  781.             $query sprintf("UPDATE %s SET nickname='%s', firstname='%s', ".
  782.                              "lastname='%s', email='%s', label='%s' ".
  783.                              "WHERE owner='%s' AND nickname='%s'",
  784.                              $this->table,
  785.                              $this->dbh->quoteString($userdata['nickname']),
  786.                              $this->dbh->quoteString($userdata['firstname']),
  787.                              $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  788.                              $this->dbh->quoteString($userdata['email']),
  789.                              $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')),
  790.                              $this->owner,
  791.                              $this->dbh->quoteString($alias) );
  792.  
  793.             /* Do the insert */
  794.             $r $this->dbh->simpleQuery($query);
  795.  
  796.             /* Check for errors */
  797.             if (DB::isError($r)) {
  798.                 return $this->set_error(sprintf(_("Database error: %s"),
  799.                                                 DB::errorMessage($r)));
  800.             }
  801.         }
  802.  
  803.         return true;
  804.     }
  805. /* End of class abook_database */
  806.  
  807. // vim: et ts=4

Documentation generated on Mon, 13 Jan 2020 04:21:53 +0100 by phpDocumentor 1.4.3