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-2016 The SquirrelMail Project Team
  7.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8.  * @version $Id: abook_database.php 14602 2016-10-29 21:53:22Z 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
  145.      * @param array $param address book backend options
  146.      */
  147.     function abook_database($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.     /**
  195.      * Open the database.
  196.      * @param bool $new new connection if it is true
  197.      * @return bool 
  198.      */
  199.     function open($new false{
  200.         global $use_pdo;
  201.         $this->error = '';
  202.  
  203.         /* Return true is file is open and $new is unset */
  204.         if ($this->dbh && !$new{
  205.             return true;
  206.         }
  207.  
  208.         /* Close old file, if any */
  209.         if ($this->dbh{
  210.             $this->close();
  211.         }
  212.  
  213.         if ($use_pdo{
  214.             // parse and convert DSN to PDO style
  215.             // Pear's full DSN syntax is one of the following:
  216.             //    phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
  217.             //    phptype(syntax)://user:pass@protocol(proto_opts)/database
  218.             //
  219.             // $matches will contain:
  220.             // 1: database type
  221.             // 2: username
  222.             // 3: password
  223.             // 4: hostname (and possible port number) OR protocol (and possible protocol options)
  224.             // 5: database name (and possible options)
  225.             // 6: port number (moved from match number 4)
  226.             // 7: options (moved from match number 5)
  227.             // 8: protocol (instead of hostname)
  228.             // 9: protocol options (moved from match number 4/8)
  229. //TODO: do we care about supporting cases where no password is given? (this is a legal DSN, but causes an error below)
  230.             if (!preg_match('|^(.+)://(.+):(.+)@(.+)/(.+)$|i'$this->dsn$matches)) {
  231.                 return $this->set_error(_("Could not parse prefs DSN"));
  232.             }
  233.             $matches[6NULL;
  234.             $matches[7NULL;
  235.             $matches[8NULL;
  236.             $matches[9NULL;
  237.             if (preg_match('|^(.+):(\d+)$|'$matches[4]$host_port_matches)) {
  238.                 $matches[4$host_port_matches[1];
  239.                 $matches[6$host_port_matches[2];
  240.             
  241.             if (preg_match('|^(.+?)\((.+)\)$|'$matches[4]$protocol_matches)) {
  242.                 $matches[8$protocol_matches[1];
  243.                 $matches[9$protocol_matches[2];
  244.                 $matches[4NULL;
  245.                 $matches[6NULL;
  246.             
  247. //TODO: currently we just ignore options specified on the end of the DSN
  248.             if (preg_match('|^(.+?)\?(.+)$|'$matches[5]$database_name_options_matches)) {
  249.                 $matches[5$database_name_options_matches[1];
  250.                 $matches[7$database_name_options_matches[2];
  251.             
  252.             if ($matches[8=== 'unix' && !empty($matches[9]))
  253.                 $pdo_prefs_dsn $matches[1':unix_socket=' $matches[9';dbname=' $matches[5];
  254.             else
  255.                 $pdo_prefs_dsn $matches[1':host=' $matches[4(!empty($matches[6]';port=' $matches[6''';dbname=' $matches[5];
  256.             try {
  257.                 $dbh new PDO($pdo_prefs_dsn$matches[2]$matches[3]);
  258.             catch (Exception $e{
  259.                 return $this->set_error(sprintf(_("Database error: %s")$e->getMessage()));
  260.             }
  261.  
  262.             $dbh->setAttribute(PDO::ATTR_CASEPDO::CASE_LOWER);
  263.  
  264.         else {
  265.             $dbh DB::connect($this->dsntrue);
  266.  
  267.             if (DB::isError($dbh)) {
  268.                 return $this->set_error(sprintf(_("Database error: %s"),
  269.                                                 DB::errorMessage($dbh)));
  270.             }
  271.  
  272.             /**
  273.              * field names are lowercased.
  274.              * We use unquoted identifiers and they use upper case in Oracle
  275.              */
  276.             $dbh->setOption('portability'DB_PORTABILITY_LOWERCASE);
  277.         }
  278.  
  279.         $this->dbh = $dbh;
  280.         return true;
  281.     }
  282.  
  283.     /**
  284.      * Close the file and forget the filehandle
  285.      */
  286.     function close({
  287.         global $use_pdo;
  288.         if ($use_pdo{
  289.             $this->dbh = NULL;
  290.         else {
  291.             $this->dbh->disconnect();
  292.             $this->dbh = false;
  293.         }
  294.     }
  295.  
  296.     /**
  297.      * Determine internal database field name given one of
  298.      * the SquirrelMail SM_ABOOK_FIELD_* constants
  299.      *
  300.      * @param integer $field The SM_ABOOK_FIELD_* contant to look up
  301.      *
  302.      * @return string The desired field name, or the string "ERROR"
  303.      *                 if the $field is not understood (the caller
  304.      *                 is responsible for handing errors)
  305.      *
  306.      */
  307.     function get_field_name($field{
  308.         switch ($field{
  309.             case SM_ABOOK_FIELD_NICKNAME:
  310.                 return 'nickname';
  311.             case SM_ABOOK_FIELD_FIRSTNAME:
  312.                 return 'firstname';
  313.             case SM_ABOOK_FIELD_LASTNAME:
  314.                 return 'lastname';
  315.             case SM_ABOOK_FIELD_EMAIL:
  316.                 return 'email';
  317.             case SM_ABOOK_FIELD_LABEL:
  318.                 return 'label';
  319.             default:
  320.                 return 'ERROR';
  321.         }
  322.     }
  323.  
  324.     /* ========================== Public ======================== */
  325.  
  326.     /**
  327.      * Search the database
  328.      * @param string $expr search expression
  329.      * @return array search results
  330.      */
  331.     function search($expr{
  332.         $ret array();
  333.         if(!$this->open()) {
  334.             return false;
  335.         }
  336.  
  337.         /* To be replaced by advanded search expression parsing */
  338.         if (is_array($expr)) {
  339.             return;
  340.         }
  341.  
  342.         // don't allow wide search when listing is disabled.
  343.         if ($expr=='*' && $this->listing{
  344.             return array();
  345.         }
  346.  
  347.         /* lowercase expression in order to make it case insensitive */
  348.         $expr strtolower($expr);
  349.  
  350.         /* escape SQL wildcards */
  351.         $expr str_replace('_''\\_'$expr);
  352.         $expr str_replace('%''\\%'$expr);
  353.  
  354.         /* Convert wildcards to SQL syntax  */
  355.         $expr str_replace('?''_'$expr);
  356.         $expr str_replace('*''%'$expr);
  357.  
  358.         $expr "%$expr%";
  359.  
  360.         global $use_pdo$pdo_show_sql_errors;
  361.         if ($use_pdo{
  362.             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 ?)'))) {
  363.                 if ($pdo_show_sql_errors)
  364.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  365.                 else
  366.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  367.             }
  368.             if (!($res $sth->execute(array($this->owner$expr'\\'$expr'\\'$expr'\\'$expr'\\')))) {
  369.                 if ($pdo_show_sql_errors)
  370.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  371.                 else
  372.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  373.             }
  374.  
  375.             while ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  376.                 array_push($retarray('nickname'  => $row['nickname'],
  377.                                        'name'      => "$row[firstname] $row[lastname]",
  378.                                        'firstname' => $row['firstname'],
  379.                                        'lastname'  => $row['lastname'],
  380.                                        'email'     => $row['email'],
  381.                                        'label'     => $row['label'],
  382.                                        'backend'   => $this->bnum,
  383.                                        'source'    => &$this->sname));
  384.             }
  385.  
  386.         else {
  387.             $expr $this->dbh->quoteString($expr);
  388.  
  389.             /* create escape expression */
  390.             $escape 'ESCAPE \'' $this->dbh->quoteString('\\''\'';
  391.  
  392.             $query sprintf("SELECT * FROM %s WHERE owner='%s' AND " .
  393.                              "(LOWER(firstname) LIKE '%s' %s " .
  394.                              "OR LOWER(lastname) LIKE '%s' %s " .
  395.                              "OR LOWER(email) LIKE '%s' %s " .
  396.                              "OR LOWER(nickname) LIKE '%s' %s)",
  397.                              $this->table$this->owner$expr$escape$expr$escape,
  398.                                                          $expr$escape$expr$escape);
  399.             $res $this->dbh->query($query);
  400.  
  401.             if (DB::isError($res)) {
  402.                 return $this->set_error(sprintf(_("Database error: %s"),
  403.                                                 DB::errorMessage($res)));
  404.             }
  405.  
  406.             while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  407.                 array_push($retarray('nickname'  => $row['nickname'],
  408.                                        'name'      => "$row[firstname] $row[lastname]",
  409.                                        'firstname' => $row['firstname'],
  410.                                        'lastname'  => $row['lastname'],
  411.                                        'email'     => $row['email'],
  412.                                        'label'     => $row['label'],
  413.                                        'backend'   => $this->bnum,
  414.                                        'source'    => &$this->sname));
  415.             }
  416.         }
  417.         return $ret;
  418.     }
  419.  
  420.     /**
  421.      * Lookup by the indicated field
  422.      *
  423.      * @param string  $value Value to look up
  424.      * @param integer $field The field to look in, should be one
  425.      *                        of the SM_ABOOK_FIELD_* constants
  426.      *                        defined in functions/constants.php
  427.      *                        (OPTIONAL; defaults to nickname field)
  428.      *                        NOTE: uniqueness is only guaranteed
  429.      *                        when the nickname field is used here;
  430.      *                        otherwise, the first matching address
  431.      *                        is returned.
  432.      *
  433.      * @return array search results
  434.      *
  435.      */
  436.     function lookup($value$field=SM_ABOOK_FIELD_NICKNAME{
  437.         if (empty($value)) {
  438.             return array();
  439.         }
  440.  
  441.         $value strtolower($value);
  442.  
  443.         if (!$this->open()) {
  444.             return false;
  445.         }
  446.  
  447.         global $use_pdo$pdo_show_sql_errors;
  448.         if ($use_pdo{
  449.             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 . ') = ?'))) {
  450.                 if ($pdo_show_sql_errors)
  451.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  452.                 else
  453.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  454.             }
  455.             if (!($res $sth->execute(array($this->owner$value)))) {
  456.                 if ($pdo_show_sql_errors)
  457.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  458.                 else
  459.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  460.             }
  461.  
  462.             if ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  463.                 return array('nickname'  => $row['nickname'],
  464.                              'name'      => "$row[firstname] $row[lastname]",
  465.                              'firstname' => $row['firstname'],
  466.                              'lastname'  => $row['lastname'],
  467.                              'email'     => $row['email'],
  468.                              'label'     => $row['label'],
  469.                              'backend'   => $this->bnum,
  470.                              'source'    => &$this->sname);
  471.             }
  472.  
  473.         else {
  474.             $query sprintf("SELECT * FROM %s WHERE owner = '%s' AND LOWER(%s) = '%s'",
  475.                              $this->table$this->owner$this->get_field_name($field)
  476.                              $this->dbh->quoteString($value));
  477.  
  478.             $res $this->dbh->query($query);
  479.  
  480.             if (DB::isError($res)) {
  481.                 return $this->set_error(sprintf(_("Database error: %s"),
  482.                                                 DB::errorMessage($res)));
  483.             }
  484.  
  485.             if ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  486.                 return array('nickname'  => $row['nickname'],
  487.                              'name'      => "$row[firstname] $row[lastname]",
  488.                              'firstname' => $row['firstname'],
  489.                              'lastname'  => $row['lastname'],
  490.                              'email'     => $row['email'],
  491.                              'label'     => $row['label'],
  492.                              'backend'   => $this->bnum,
  493.                              'source'    => &$this->sname);
  494.             }
  495.         }
  496.  
  497.         return array();
  498.     }
  499.  
  500.     /**
  501.      * List all addresses
  502.      * @return array search results
  503.      */
  504.     function list_addr({
  505.         $ret array();
  506.         if (!$this->open()) {
  507.             return false;
  508.         }
  509.  
  510.         if(isset($this->listing&& !$this->listing{
  511.             return array();
  512.         }
  513.  
  514.  
  515.         global $use_pdo$pdo_show_sql_errors;
  516.         if ($use_pdo{
  517.             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 . ' = ?'))) {
  518.                 if ($pdo_show_sql_errors)
  519.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  520.                 else
  521.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  522.             }
  523.             if (!($res $sth->execute(array($this->owner)))) {
  524.                 if ($pdo_show_sql_errors)
  525.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  526.                 else
  527.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  528.             }
  529.  
  530.             while ($row $sth->fetch(PDO::FETCH_ASSOC)) {
  531.                 array_push($retarray('nickname'  => $row['nickname'],
  532.                                        'name'      => "$row[firstname] $row[lastname]",
  533.                                        'firstname' => $row['firstname'],
  534.                                        'lastname'  => $row['lastname'],
  535.                                        'email'     => $row['email'],
  536.                                        'label'     => $row['label'],
  537.                                        'backend'   => $this->bnum,
  538.                                        'source'    => &$this->sname));
  539.             }
  540.         else {
  541.             $query sprintf("SELECT * FROM %s WHERE owner='%s'",
  542.                              $this->table$this->owner);
  543.  
  544.             $res $this->dbh->query($query);
  545.  
  546.             if (DB::isError($res)) {
  547.                 return $this->set_error(sprintf(_("Database error: %s"),
  548.                                                 DB::errorMessage($res)));
  549.             }
  550.  
  551.             while ($row $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  552.                 array_push($retarray('nickname'  => $row['nickname'],
  553.                                        'name'      => "$row[firstname] $row[lastname]",
  554.                                        'firstname' => $row['firstname'],
  555.                                        'lastname'  => $row['lastname'],
  556.                                        'email'     => $row['email'],
  557.                                        'label'     => $row['label'],
  558.                                        'backend'   => $this->bnum,
  559.                                        'source'    => &$this->sname));
  560.             }
  561.         }
  562.  
  563.         return $ret;
  564.     }
  565.  
  566.     /**
  567.      * Add address
  568.      * @param array $userdata added data
  569.      * @return bool 
  570.      */
  571.     function add($userdata{
  572.         if (!$this->writeable{
  573.             return $this->set_error(_("Address book is read-only"));
  574.         }
  575.  
  576.         if (!$this->open()) {
  577.             return false;
  578.         }
  579.  
  580.         // NB: if you want to check for some unwanted characters
  581.         //     or other problems, do so here like this:
  582.         // TODO: Should pull all validation code out into a separate function
  583.         //if (strpos($userdata['nickname'], ' ')) {
  584.         //    return $this->set_error(_("Nickname contains illegal characters"));
  585.         //}
  586.  
  587.         /* See if user exist already */
  588.         $ret $this->lookup($userdata['nickname']);
  589.         if (!empty($ret)) {
  590.             return $this->set_error(sprintf(_("User \"%s\" already exists")$ret['nickname']));
  591.         }
  592.  
  593.         global $use_pdo$pdo_show_sql_errors;
  594.         if ($use_pdo{
  595.             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 (?, ?, ?, ?, ?, ?)'))) {
  596.                 if ($pdo_show_sql_errors)
  597.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  598.                 else
  599.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  600.             }
  601.             if (!($res $sth->execute(array($this->owner$userdata['nickname']$userdata['firstname'](!empty($userdata['lastname']$userdata['lastname''')$userdata['email'](!empty($userdata['label']$userdata['label'''))))) {
  602.                 if ($pdo_show_sql_errors)
  603.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  604.                 else
  605.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  606.             }
  607.         else {
  608.             /* Create query */
  609.             $query sprintf("INSERT INTO %s (owner, nickname, firstname, " .
  610.                              "lastname, email, label) VALUES('%s','%s','%s'," .
  611.                              "'%s','%s','%s')",
  612.                              $this->table$this->owner,
  613.                              $this->dbh->quoteString($userdata['nickname']),
  614.                              $this->dbh->quoteString($userdata['firstname']),
  615.                              $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  616.                              $this->dbh->quoteString($userdata['email']),
  617.                              $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')) );
  618.  
  619.             /* Do the insert */
  620.             $r $this->dbh->simpleQuery($query);
  621.  
  622.             /* Check for errors */
  623.             if (DB::isError($r)) {
  624.                 return $this->set_error(sprintf(_("Database error: %s"),
  625.                                                 DB::errorMessage($r)));
  626.             }
  627.         }
  628.  
  629.          return true;
  630.     }
  631.  
  632.     /**
  633.      * Delete address
  634.      * @param string $alias alias that has to be deleted
  635.      * @return bool 
  636.      */
  637.     function remove($alias{
  638.         if (!$this->writeable{
  639.             return $this->set_error(_("Address book is read-only"));
  640.         }
  641.  
  642.         if (!$this->open()) {
  643.             return false;
  644.         }
  645.  
  646.         global $use_pdo$pdo_show_sql_errors;
  647.         if ($use_pdo{
  648.             $sepstr '';
  649.             $where_clause '';
  650.             $where_clause_args array();
  651.             while (list($undef$nicknameeach($alias)) {
  652.                 $where_clause .= $sepstr $this->identifier_quote_char . 'nickname' $this->identifier_quote_char . ' = ?';
  653.                 $where_clause_args[$nickname;
  654.                 $sepstr ' OR ';
  655.             }
  656.             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 ')'))) {
  657.                 if ($pdo_show_sql_errors)
  658.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  659.                 else
  660.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  661.             }
  662.             array_unshift($where_clause_args$this->owner);
  663.             if (!($res $sth->execute($where_clause_args))) {
  664.                 if ($pdo_show_sql_errors)
  665.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  666.                 else
  667.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  668.             }
  669.         else {
  670.             /* Create query */
  671.             $query sprintf("DELETE FROM %s WHERE owner='%s' AND (",
  672.                              $this->table$this->owner);
  673.  
  674.             $sepstr '';
  675.             while (list($undef$nicknameeach($alias)) {
  676.                 $query .= sprintf("%s nickname='%s' "$sepstr,
  677.                                   $this->dbh->quoteString($nickname));
  678.                 $sepstr 'OR';
  679.             }
  680.             $query .= ')';
  681.  
  682.             /* Delete entry */
  683.             $r $this->dbh->simpleQuery($query);
  684.  
  685.             /* Check for errors */
  686.             if (DB::isError($r)) {
  687.                 return $this->set_error(sprintf(_("Database error: %s"),
  688.                                                 DB::errorMessage($r)));
  689.             }
  690.         }
  691.  
  692.         return true;
  693.     }
  694.  
  695.     /**
  696.      * Modify address
  697.      * @param string $alias modified alias
  698.      * @param array $userdata new data
  699.      * @return bool 
  700.      */
  701.     function modify($alias$userdata{
  702.         if (!$this->writeable{
  703.             return $this->set_error(_("Address book is read-only"));
  704.         }
  705.  
  706.         if (!$this->open()) {
  707.             return false;
  708.         }
  709.  
  710.         // NB: if you want to check for some unwanted characters
  711.         //     or other problems, do so here like this:
  712.         // TODO: Should pull all validation code out into a separate function
  713.         //if (strpos($userdata['nickname'], ' ')) {
  714.         //    return $this->set_error(_("Nickname contains illegal characters"));
  715.         //}
  716.  
  717.          /* See if user exist */
  718.         $ret $this->lookup($alias);
  719.         if (empty($ret)) {
  720.             return $this->set_error(sprintf(_("User \"%s\" does not exist")$alias));
  721.         }
  722.  
  723.         /* make sure that new nickname is not used */
  724.         if (strtolower($alias!= strtolower($userdata['nickname'])) {
  725.             /* same check as in add() */
  726.             $ret $this->lookup($userdata['nickname']);
  727.             if (!empty($ret)) {
  728.                 $error sprintf(_("User '%s' already exist.")$ret['nickname']);
  729.                 return $this->set_error($error);
  730.             }
  731.         }
  732.  
  733.         global $use_pdo$pdo_show_sql_errors;
  734.         if ($use_pdo{
  735.             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 . ' = ?'))) {
  736.                 if ($pdo_show_sql_errors)
  737.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$this->dbh->errorInfo())));
  738.                 else
  739.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not prepare query")));
  740.             }
  741.             if (!($res $sth->execute(array($userdata['nickname']$userdata['firstname'](!empty($userdata['lastname']$userdata['lastname''')$userdata['email'](!empty($userdata['label']$userdata['label''')$this->owner$alias)))) {
  742.                 if ($pdo_show_sql_errors)
  743.                     return $this->set_error(sprintf(_("Database error: %s")implode(' - '$sth->errorInfo())));
  744.                 else
  745.                     return $this->set_error(sprintf(_("Database error: %s")_("Could not execute query")));
  746.             }
  747.         else {
  748.             /* Create query */
  749.             $query sprintf("UPDATE %s SET nickname='%s', firstname='%s', ".
  750.                              "lastname='%s', email='%s', label='%s' ".
  751.                              "WHERE owner='%s' AND nickname='%s'",
  752.                              $this->table,
  753.                              $this->dbh->quoteString($userdata['nickname']),
  754.                              $this->dbh->quoteString($userdata['firstname']),
  755.                              $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
  756.                              $this->dbh->quoteString($userdata['email']),
  757.                              $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')),
  758.                              $this->owner,
  759.                              $this->dbh->quoteString($alias) );
  760.  
  761.             /* Do the insert */
  762.             $r $this->dbh->simpleQuery($query);
  763.  
  764.             /* Check for errors */
  765.             if (DB::isError($r)) {
  766.                 return $this->set_error(sprintf(_("Database error: %s"),
  767.                                                 DB::errorMessage($r)));
  768.             }
  769.         }
  770.  
  771.         return true;
  772.     }
  773. /* End of class abook_database */
  774.  
  775. // vim: et ts=4

Documentation generated on Wed, 07 Dec 2016 04:23:23 +0100 by phpDocumentor 1.4.3