Source for file abook_database.php

Documentation is available at abook_database.php

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

Documentation generated on Mon, 13 Jan 2020 04:24:09 +0100 by phpDocumentor 1.4.3