adding database field size checks (#1233721)
authortokul <tokul@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Sat, 10 Sep 2005 08:46:15 +0000 (08:46 +0000)
committertokul <tokul@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Sat, 10 Sep 2005 08:46:15 +0000 (08:46 +0000)
git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@10083 7612ce4b-ef26-0410-bec9-ea0150e637f0

config/conf.pl
config/config_default.php
doc/db-backend.txt
functions/db_prefs.php
plugins/administrator/defines.php

index 2236d04..4f7a175 100755 (executable)
@@ -360,6 +360,9 @@ $abook_global_file_listing = 'true'     if ( !$abook_global_file_listing );
 $encode_header_key = ''                 if ( !$encode_header_key );
 $hide_auth_header = 'false'             if ( !$hide_auth_header );
 $time_zone_type = '0'                   if ( !$time_zone_type );
+$prefs_user_size = 128                  if ( !$prefs_user_size );
+$prefs_key_size = 64                    if ( !$prefs_key_size );
+$prefs_val_size = 65536                 if ( !$prefs_val_size );
 
 if ( $ARGV[0] eq '--install-plugin' ) {
     print "Activating plugin " . $ARGV[1] . "\n";
@@ -608,9 +611,9 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) {
         print "\n";
         print "3.  DSN for Preferences    : $WHT$prefs_dsn$NRM\n";
         print "4.  Table for Preferences  : $WHT$prefs_table$NRM\n";
-        print "5.  Field for username     : $WHT$prefs_user_field$NRM\n";
-        print "6.  Field for prefs key    : $WHT$prefs_key_field$NRM\n";
-        print "7.  Field for prefs value  : $WHT$prefs_val_field$NRM\n";
+        print "5.  Field for username     : $WHT$prefs_user_field$NRM ($prefs_user_size)\n";
+        print "6.  Field for prefs key    : $WHT$prefs_key_field$NRM ($prefs_key_size)\n";
+        print "7.  Field for prefs value  : $WHT$prefs_val_field$NRM ($prefs_val_size)\n";
         print "\n";
         print "8.  DSN for Global Address Book            : $WHT$addrbook_global_dsn$NRM\n";
         print "9.  Table for Global Address Book          : $WHT$addrbook_global_table$NRM\n";
@@ -2964,6 +2967,7 @@ sub command95 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_user_size = db_pref_size($prefs_user_size);
     return $new_field;
 }
 
@@ -2978,6 +2982,7 @@ sub command96 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_key_size = db_pref_size($prefs_key_size);
     return $new_field;
 }
 
@@ -2992,9 +2997,26 @@ sub command97 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_val_size = db_pref_size($prefs_val_size);
     return $new_field;
 }
 
+# routine is used to set database field limits
+# it needs one argument
+sub db_pref_size() {
+    my ($size) = $_[0];
+    print "\nDatabase fields have size limits.\n";
+    print "\n";
+    print "What limit is set for this field? [$WHT$size$NRM]: $WHT";
+    $new_size = <STDIN>;
+    if ( $new_size eq "\n" ) {
+        $new_size = $size;
+    } else {
+        $new_size =~ s/[\r\n]//g;
+    }
+    return $new_size;
+}
+
 sub command98 {
     print "If you want to store your global address book in a database then\n";
     print "you need to set this DSN to a valid value. The format for this is:\n";
@@ -3583,10 +3605,16 @@ sub save_data {
         print CF "\$prefs_table = '$prefs_table';\n";
     # string
         print CF "\$prefs_user_field = '$prefs_user_field';\n";
+    # integer
+        print CF "\$prefs_user_size = $prefs_user_size;\n";
     # string
         print CF "\$prefs_key_field = '$prefs_key_field';\n";
+    # integer
+        print CF "\$prefs_key_size = $prefs_key_size;\n";
     # string
-        print CF "\$prefs_val_field = '$prefs_val_field';\n\n";
+        print CF "\$prefs_val_field = '$prefs_val_field';\n";
+    # integer
+        print CF "\$prefs_val_size = $prefs_val_size;\n\n";
     # string
         print CF "\$addrbook_global_dsn = '$addrbook_global_dsn';\n";
     # string
index 90e8ede..cdeb9a3 100644 (file)
@@ -845,9 +845,39 @@ $addrbook_table = 'address';
  */
 $prefs_dsn = '';
 $prefs_table = 'userprefs';
+/**
+ * Preference key field 
+ * @global string $prefs_key_field
+ */
 $prefs_key_field = 'prefkey';
+/**
+ * Size of preference key field
+ * @global integer $prefs_key_size
+ * @since 1.5.1
+ */
+$prefs_key_size = 64;
+/**
+ * Preference owner field 
+ * @global string $prefs_user_field
+ */
 $prefs_user_field = 'user';
+/**
+ * Size of preference owner field
+ * @global integer $prefs_user_size
+ * @since 1.5.1
+ */
+$prefs_user_size = 128;
+/**
+ * Preference value field 
+ * @global string $prefs_val_field
+ */
 $prefs_val_field = 'prefval';
+/**
+ * Size of preference key field
+ * @global integer $prefs_val_size
+ * @since 1.5.1
+ */
+$prefs_val_size = 65536;
 
 /*** Global sql database options ***/
 /**
index 3315543..3942b40 100644 (file)
@@ -118,3 +118,24 @@ database.
 
 Default preferences can be set by altering the $default array in
 db_prefs.php.
+
+Troubleshooting
+---------------
+1. Oversized field values. Preferences are not/can't be saved
+
+Database fields have size limits. Preference table example sets 128 
+character limit to owner field, 64 character limit to preference key 
+field and 64KB (database BLOB field size) limit to value field.
+
+If interface tries to insert data without checking field limits, it
+can cause data loss or database errors. Table information functions
+provided by Pear DB libraries are not accurate and some database 
+backends don't support them. Since 1.5.1 SquirrelMail provides
+configuration options that set allowed field sizes.
+
+If you see oversized field errors in your error logs - check your 
+database structure. Issue can be solved by increasing database field 
+sizes.
+
+If you want to get more debugging information - check setKey() function 
+in dbPrefs class. Class is stored in functions/db_prefs.php
index fe1d425..63db4a2 100644 (file)
@@ -143,12 +143,32 @@ class dbPrefs {
                          'show_html_default' => '0');
 
     /**
+     * Preference owner field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $user_size = 128;
+    /**
+     * Preference key field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $key_size = 64;
+    /**
+     * Preference value field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $val_size = 65536;
+
+    /**
      * initialize DB connection object
      * @return boolean true, if object is initialized
      */
     function open() {
         global $prefs_dsn, $prefs_table;
         global $prefs_user_field, $prefs_key_field, $prefs_val_field;
+        global $prefs_user_size, $prefs_key_size, $prefs_val_size;
 
         if(isset($this->dbh)) {
             return true;
@@ -172,6 +192,15 @@ class dbPrefs {
         if (!empty($prefs_val_field)) {
             $this->val_field = $prefs_val_field;
         }
+        if (!empty($prefs_user_size)) {
+            $this->user_size = (int) $prefs_user_size;
+        }
+        if (!empty($prefs_key_size)) {
+            $this->key_size = (int) $prefs_key_size;
+        }
+        if (!empty($prefs_val_size)) {
+            $this->val_size = (int) $prefs_val_size;
+        }
         $dbh = DB::connect($prefs_dsn, true);
 
         if(DB::isError($dbh)) {
@@ -261,6 +290,46 @@ class dbPrefs {
         if (!$this->open()) {
             return false;
         }
+
+        /**
+         * Check if username fits into db field
+         */
+        if (strlen($user) > $this->user_size) {
+            $this->error = "Oversized username value."
+                ." User's preferences can't be saved. See doc/db-backend.txt troubleshooting documentation.";
+
+            /**
+             * Debugging function. Can be used to log all issues that trigger 
+             * oversized field errors. Function should be enabled in all three 
+             * strlen checks. See http://www.php.net/error-log
+             */
+            // error_log($user.'|'.$key.'|'.$value."\n",3,'/tmp/oversized_log');
+
+            // error is fatal
+            $this->failQuery(null);
+        }
+        /**
+         * Check if preference key fits into db field
+         */
+        if (strlen($key) > $this->key_size) {
+            $err_msg = "Oversized user's preference key."
+                ." Some user preferences are not saved. See doc/db-backend.txt troubleshooting documentation.";
+            // error is not fatal. Only some preference is not saved.
+            trigger_error($err_msg,E_USER_WARNING);
+            return false;
+        }
+        /**
+         * Check if preference value fits into db field
+         */
+        if (strlen($value) > $this->val_size) {
+            $err_msg = "Oversized user's preference value."
+                ." Some user preferences are not saved. See doc/db-backend.txt troubleshooting documentation.";
+            // error is not fatal. Only some preference is not saved.
+            trigger_error($err_msg,E_USER_WARNING);
+            return false;
+        }
+
+
         if ($this->db_type == SMDB_MYSQL) {
             $query = sprintf("REPLACE INTO %s (%s, %s, %s) ".
                              "VALUES('%s','%s','%s')",
index e5deb8b..c8b6018 100644 (file)
@@ -289,14 +289,20 @@ $defcfg = array( '$config_version' => array( 'name' => _("Config File Version"),
                                               'type' => SMOPT_TYPE_STRING,
                                               'size' => 40,
                                               'default' => 'user' ),
+                 '$prefs_user_size' => array( 'name' => _("Size of username field"),
+                                              'type' => SMOPT_TYPE_INTEGER ),
                  '$prefs_key_field' => array('name' => _("Preferences key field"),
                                              'type' => SMOPT_TYPE_STRING,
                                              'size' => 40,
                                              'default' => 'prefkey' ),
+                 '$prefs_key_size' => array( 'name' => _("Size of key field"),
+                                             'type' => SMOPT_TYPE_INTEGER ),
                  '$prefs_val_field' => array('name' => _("Preferences value field"),
                                              'type' => SMOPT_TYPE_STRING,
                                              'size' => 40,
                                              'default' => 'prefval' ),
+                 '$prefs_val_size' => array( 'name' => _("Size of value field"),
+                                             'type' => SMOPT_TYPE_INTEGER ),
                  '$addrbook_global_dsn' => array( 'name' => _("Global address book DSN"),
                                            'type' => SMOPT_TYPE_STRING,
                                            'size' => 40 ),