]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch 'utf8mb4' into nightly
authorMikael Nordfeldth <mmn@hethane.se>
Thu, 19 Feb 2015 19:50:40 +0000 (20:50 +0100)
committerMikael Nordfeldth <mmn@hethane.se>
Thu, 19 Feb 2015 19:50:40 +0000 (20:50 +0100)
Conflicts because of urlhash fixes:
classes/File.php
classes/File_redirection.php
classes/File_thumbnail.php

1  2 
classes/File.php
classes/File_thumbnail.php
classes/Profile.php
classes/Subscription.php
classes/User.php
extlib/DB.php
plugins/Blog/classes/Blog_entry.php
plugins/OStatus/classes/Ostatus_profile.php

diff --combined classes/File.php
index 716e1cc2c6c449e84729fd94f48861706a1fc5be,b42e1a674fb012d642438ccdf96b4a7f71d8aca2..b4bf9f9a1fdc046885d7cf9c4dafdb7b4b226678
@@@ -26,33 -26,29 +26,33 @@@ class File extends Managed_DataObjec
  {
      public $__table = 'file';                            // table name
      public $id;                              // int(4)  primary_key not_null
 -    public $url;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
 +    public $urlhash;                         // varchar(64)  unique_key
 +    public $url;                             // text
      public $mimetype;                        // varchar(50)
      public $size;                            // int(4)
-     public $title;                           // varchar(255)
+     public $title;                           // varchar(191)   not 255 because utf8mb4 takes more space
      public $date;                            // int(4)
      public $protected;                       // int(4)
-     public $filename;                        // varchar(255)
+     public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
      public $width;                           // int(4)
      public $height;                          // int(4)
      public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
  
 +    const URLHASH_ALG = 'sha256';
 +
      public static function schemaDef()
      {
          return array(
              'fields' => array(
                  'id' => array('type' => 'serial', 'not null' => true),
 -                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'destination URL after following redirections'),
 +                'urlhash' => array('type' => 'varchar', 'length' => 64, 'description' => 'sha256 of destination URL (url field)'),
 +                'url' => array('type' => 'text', 'description' => 'destination URL after following redirections'),
                  'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
                  'size' => array('type' => 'int', 'description' => 'size of resource when available'),
-                 'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of resource when available'),
+                 'title' => array('type' => 'varchar', 'length' => 191, 'description' => 'title of resource when available'),
                  'date' => array('type' => 'int', 'description' => 'date of resource according to http query'),
                  'protected' => array('type' => 'int', 'description' => 'true when URL is private (needs login)'),
-                 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if a local file, name of the file'),
+                 'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if a local file, name of the file'),
                  'width' => array('type' => 'int', 'description' => 'width in pixels, if it can be described as such and data is available'),
                  'height' => array('type' => 'int', 'description' => 'height in pixels, if it can be described as such and data is available'),
  
@@@ -60,7 -56,7 +60,7 @@@
              ),
              'primary key' => array('id'),
              'unique keys' => array(
 -                'file_url_key' => array('url'),
 +                'file_urlhash_key' => array('urlhash'),
              ),
          );
      }
          // I don't know why we have to keep doing this but I'm adding this last check to avoid
          // uniqueness bugs.
  
 -        $file = File::getKV('url', $given_url);
 +        $file = File::getKV('urlhash', self::hashurl($given_url));
          
          if (!$file instanceof File) {
              $file = new File;
 +            $file->urlhash = self::hashurl($given_url);
              $file->url = $given_url;
              if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
              if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
              throw new ServerException('No canonical URL from given URL to process');
          }
  
 -        $file = File::getKV('url', $given_url);
 -        if (!$file instanceof File) {
 +        $file = null;
 +
 +        try {
 +            $file = File::getByUrl($given_url);
 +        } catch (NoResultException $e) {
              // First check if we have a lookup trace for this URL already
 -            $file_redir = File_redirection::getKV('url', $given_url);
 -            if ($file_redir instanceof File_redirection) {
 +            try {
 +                $file_redir = File_redirection::getByUrl($given_url);
                  $file = File::getKV('id', $file_redir->file_id);
                  if (!$file instanceof File) {
                      // File did not exist, let's clean up the File_redirection entry
                      $file_redir->delete();
                  }
 +            } catch (NoResultException $e) {
 +                // We just wanted to doublecheck whether a File_thumbnail we might've had
 +                // actually referenced an existing File object.
              }
 +        }
  
 -            // If we still don't have a File object, let's create one now!
 -            if (!$file instanceof File) {
 -                // @fixme for new URLs this also looks up non-redirect data
 -                // such as target content type, size, etc, which we need
 -                // for File::saveNew(); so we call it even if not following
 -                // new redirects.
 -                $redir_data = File_redirection::where($given_url);
 -                if (is_array($redir_data)) {
 -                    $redir_url = $redir_data['url'];
 -                } elseif (is_string($redir_data)) {
 -                    $redir_url = $redir_data;
 -                    $redir_data = array();
 -                } else {
 -                    // TRANS: Server exception thrown when a URL cannot be processed.
 -                    throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
 -                }
 +        // If we still don't have a File object, let's create one now!
 +        if (!$file instanceof File) {
 +            // @fixme for new URLs this also looks up non-redirect data
 +            // such as target content type, size, etc, which we need
 +            // for File::saveNew(); so we call it even if not following
 +            // new redirects.
 +            $redir_data = File_redirection::where($given_url);
 +            if (is_array($redir_data)) {
 +                $redir_url = $redir_data['url'];
 +            } elseif (is_string($redir_data)) {
 +                $redir_url = $redir_data;
 +                $redir_data = array();
 +            } else {
 +                // TRANS: Server exception thrown when a URL cannot be processed.
 +                throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
 +            }
  
 -                // TODO: max field length
 -                if ($redir_url === $given_url || strlen($redir_url) > 191 || !$followRedirects) {
 -                    // Save the File object based on our lookup trace
 -                    $file = File::saveNew($redir_data, $given_url);
 -                } else {
 -                    // This seems kind of messed up... for now skipping this part
 -                    // if we're already under a redirect, so we don't go into
 -                    // horrible infinite loops if we've been given an unstable
 -                    // redirect (where the final destination of the first request
 -                    // doesn't match what we get when we ask for it again).
 -                    //
 -                    // Seen in the wild with clojure.org, which redirects through
 -                    // wikispaces for auth and appends session data in the URL params.
 -                    $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
 -                    File_redirection::saveNew($redir_data, $file->id, $given_url);
 -                }
 +            if ($redir_url === $given_url || !$followRedirects) {
 +                // Save the File object based on our lookup trace
 +                $file = File::saveNew($redir_data, $given_url);
 +            } else {
 +                // This seems kind of messed up... for now skipping this part
 +                // if we're already under a redirect, so we don't go into
 +                // horrible infinite loops if we've been given an unstable
 +                // redirect (where the final destination of the first request
 +                // doesn't match what we get when we ask for it again).
 +                //
 +                // Seen in the wild with clojure.org, which redirects through
 +                // wikispaces for auth and appends session data in the URL params.
 +                $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
 +                File_redirection::saveNew($redir_data, $file->id, $given_url);
              }
  
              if (!$file instanceof File) {
          if (!empty($this->filename)) {
              // A locally stored file, so let's generate a URL for our instance.
              $url = self::url($this->filename);
 -            if ($url != $this->url) {
 +            if (self::hashurl($url) !== $this->urlhash) {
                  // For indexing purposes, in case we do a lookup on the 'url' field.
                  // also we're fixing possible changes from http to https, or paths
                  $this->updateUrl($url);
          return $this->url;
      }
  
 +    static public function getByUrl($url)
 +    {
 +        $file = new File();
 +        $file->urlhash = self::hashurl($url);
 +        if (!$file->find(true)) {
 +            throw new NoResultException($file);
 +        }
 +        return $file;
 +    }
 +
      public function updateUrl($url)
      {
 -        $file = File::getKV('url', $url);
 +        $file = File::getKV('urlhash', self::hashurl($url));
          if ($file instanceof File) {
              throw new ServerException('URL already exists in DB');
          }
 -        $sql = 'UPDATE %1$s SET url=%2$s WHERE url=%3$s;';
 +        $sql = 'UPDATE %1$s SET urlhash=%2$s, url=%3$s WHERE urlhash=%4$s;';
          $result = $this->query(sprintf($sql, $this->__table,
 +                                             $this->_quote((string)self::hashurl($url)),
                                               $this->_quote((string)$url),
 -                                             $this->_quote((string)$this->url)));
 +                                             $this->_quote((string)$this->urlhash)));
          if ($result === false) {
              common_log_db_error($this, 'UPDATE', __FILE__);
              throw new ServerException("Could not UPDATE {$this->__table}.url");
  
      function blowCache($last=false)
      {
 -        self::blow('file:notice-ids:%s', $this->url);
 +        self::blow('file:notice-ids:%s', $this->urlhash);
          if ($last) {
 -            self::blow('file:notice-ids:%s;last', $this->url);
 +            self::blow('file:notice-ids:%s;last', $this->urlhash);
          }
          self::blow('file:notice-count:%d', $this->id);
      }
  
          return $title ?: null;
      }
 +
 +    static public function hashurl($url)
 +    {
 +        if (empty($url)) {
 +            throw new Exception('No URL provided to hash algorithm.');
 +        }
 +        return hash(self::URLHASH_ALG, $url);
 +    }
 +
 +    static public function beforeSchemaUpdate()
 +    {
 +        $table = strtolower(get_called_class());
 +        $schema = Schema::get();
 +        $schemadef = $schema->getTableDef($table);
 +
 +        // 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
 +        if (isset($schemadef['fields']['urlhash']) && isset($schemadef['unique keys']['file_urlhash_key'])) {
 +            // We already have the urlhash field, so no need to migrate it.
 +            return;
 +        }
 +        echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
 +        // We have to create a urlhash that is _not_ the primary key,
 +        // transfer data and THEN run checkSchema
 +        $schemadef['fields']['urlhash'] = array (
 +                                              'type' => 'varchar',
 +                                              'length' => 64,
 +                                              'description' => 'sha256 of destination URL after following redirections',
 +                                            );
 +        $schema->ensureTable($table, $schemadef);
 +        echo "DONE.\n";
 +
 +        $classname = ucfirst($table);
 +        $tablefix = new $classname;
 +        // urlhash is hash('sha256', $url) in the File table
 +        echo "Updating urlhash fields in $table table...";
 +        // Maybe very MySQL specific :(
 +        $tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
 +                            $schema->quoteIdentifier($table),
 +                            'urlhash',
 +                            // The line below is "result of sha256 on column `url`"
 +                            'SHA2(url, 256)'));
 +        echo "DONE.\n";
 +        echo "Resuming core schema upgrade...";
 +    }
  }
index 02d42c41ff96357d21885d12e895dc945dfa5811,af3551028e804182f8abacd230d73e3da465018e..609f1c34b8f0a0427b24f6341071808891cccb45
@@@ -27,8 -27,8 +27,8 @@@ class File_thumbnail extends Managed_Da
  {
      public $__table = 'file_thumbnail';                  // table name
      public $file_id;                         // int(4)  primary_key not_null
 -    public $url;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
 +    public $url;                             // text
-     public $filename;                        // varchar(255)
+     public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
      public $width;                           // int(4)  primary_key
      public $height;                          // int(4)  primary_key
      public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
@@@ -38,8 -38,8 +38,8 @@@
          return array(
              'fields' => array(
                  'file_id' => array('type' => 'int', 'not null' => true, 'description' => 'thumbnail for what URL/file'),
 -                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of thumbnail'),
 +                'url' => array('type' => 'text', 'description' => 'URL of thumbnail'),
-                 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if stored locally, filename is put here'),
+                 'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if stored locally, filename is put here'),
                  'width' => array('type' => 'int', 'description' => 'width of thumbnail'),
                  'height' => array('type' => 'int', 'description' => 'height of thumbnail'),
                  'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
diff --combined classes/Profile.php
index 6ae1b90011e1d6472ede0754e1258e32a65b71a0,b1c29041dffdddd8e20995d18b0f5c838cb62fca..3c3b3475b955988386b566bef7853ed33371ba9a
@@@ -30,11 -30,11 +30,11 @@@ class Profile extends Managed_DataObjec
      public $__table = 'profile';                         // table name
      public $id;                              // int(4)  primary_key not_null
      public $nickname;                        // varchar(64)  multiple_key not_null
-     public $fullname;                        // varchar(255)  multiple_key
-     public $profileurl;                      // varchar(255)
-     public $homepage;                        // varchar(255)  multiple_key
+     public $fullname;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
+     public $profileurl;                      // varchar(191)                 not 255 because utf8mb4 takes more space
+     public $homepage;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
      public $bio;                             // text()  multiple_key
-     public $location;                        // varchar(255)  multiple_key
+     public $location;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
      public $lat;                             // decimal(10,7)
      public $lon;                             // decimal(10,7)
      public $location_id;                     // int(4)
              'fields' => array(
                  'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
                  'nickname' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username', 'collate' => 'utf8_general_ci'),
-                 'fullname' => array('type' => 'varchar', 'length' => 255, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
-                 'profileurl' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL, cached so we dont regenerate'),
-                 'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
+                 'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
+                 'profileurl' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
+                 'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
                  'bio' => array('type' => 'text', 'description' => 'descriptive biography', 'collate' => 'utf8_general_ci'),
-                 'location' => array('type' => 'varchar', 'length' => 255, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
+                 'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
                  'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'),
                  'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'),
                  'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
          return $feed;
      }
  
 +    public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
 +    {
 +        // TRANS: Exception thrown when trying view "repeated to me".
 +        throw new Exception(_('Not implemented since inbox change.'));
 +    }
 +
      /*
       * Get a Profile object by URI. Will call external plugins for help
       * using the event StartGetProfileFromURI.
diff --combined classes/Subscription.php
index cd9ae3cce519ec0ab6079747c305cd5bf230ba73,9ef19e2f669f9e8e61e5e06e942c11c393d263d2..5c5101ad1d1bb430ed0493037782b0ed4c0c87b9
@@@ -32,9 -32,9 +32,9 @@@ class Subscription extends Managed_Data
      public $subscribed;                      // int(4)  primary_key not_null
      public $jabber;                          // tinyint(1)   default_1
      public $sms;                             // tinyint(1)   default_1
-     public $token;                           // varchar(255)
-     public $secret;                          // varchar(255)
-     public $uri;                             // varchar(255)
+     public $token;                           // varchar(191)   not 255 because utf8mb4 takes more space
+     public $secret;                          // varchar(191)   not 255 because utf8mb4 takes more space
+     public $uri;                             // varchar(191)   not 255 because utf8mb4 takes more space
      public $created;                         // datetime()   not_null
      public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
  
@@@ -46,9 -46,9 +46,9 @@@
                  'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'profile being listened to'),
                  'jabber' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver jabber messages'),
                  'sms' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver sms messages'),
-                 'token' => array('type' => 'varchar', 'length' => 255, 'description' => 'authorization token'),
-                 'secret' => array('type' => 'varchar', 'length' => 255, 'description' => 'token secret'),
-                 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+                 'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'authorization token'),
+                 'secret' => array('type' => 'varchar', 'length' => 191, 'description' => 'token secret'),
+                 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
                  'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                  'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
              ),
  
      static function exists(Profile $subscriber, Profile $other)
      {
 -        $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id,
 -                                           'subscribed' => $other->id));
 -        return ($sub instanceof Subscription);
 +        try {
 +            $sub = self::getSubscription($subscriber, $other);
 +        } catch (NoResultException $e) {
 +            return false;
 +        }
 +
 +        return true;
 +    }
 +
 +    static function getSubscription(Profile $subscriber, Profile $other)
 +    {
 +        // This is essentially a pkeyGet but we have an object to return in NoResultException
 +        $sub = new Subscription();
 +        $sub->subscriber = $subscriber->id;
 +        $sub->subscribed = $other->id;
 +        if (!$sub->find(true)) {
 +            throw new NoResultException($sub);
 +        }
 +        return $sub;
      }
  
      function asActivity()
diff --combined classes/User.php
index 6e42daa90cd52df4e9d92135445072d4d8f6ad99,a719bec8eff0fab3b42a65893a7772353eeffdd6..c7c91c8ec602bc2da65ed1cd12932f449325b860
@@@ -34,9 -34,9 +34,9 @@@ class User extends Managed_DataObjec
      public $__table = 'user';                            // table name
      public $id;                              // int(4)  primary_key not_null
      public $nickname;                        // varchar(64)  unique_key
-     public $password;                        // varchar(255)
-     public $email;                           // varchar(255)  unique_key
-     public $incomingemail;                   // varchar(255)  unique_key
+     public $password;                        // varchar(191)               not 255 because utf8mb4 takes more space
+     public $email;                           // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+     public $incomingemail;                   // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
      public $emailnotifysub;                  // tinyint(1)   default_1
      public $emailnotifyfav;                  // tinyint(1)   default_1
      public $emailnotifynudge;                // tinyint(1)   default_1
@@@ -50,8 -50,8 +50,8 @@@
      public $carrier;                         // int(4)
      public $smsnotify;                       // tinyint(1)
      public $smsreplies;                      // tinyint(1)
-     public $smsemail;                        // varchar(255)
-     public $uri;                             // varchar(255)  unique_key
+     public $smsemail;                        // varchar(191)               not 255 because utf8mb4 takes more space
+     public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
      public $autosubscribe;                   // tinyint(1)
      public $subscribe_policy;                // tinyint(1)
      public $urlshorteningservice;            // varchar(50)   default_ur1.ca
@@@ -69,9 -69,9 +69,9 @@@
              'fields' => array(
                  'id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
                  'nickname' => array('type' => 'varchar', 'length' => 64, 'description' => 'nickname or username, duped in profile'),
-                 'password' => array('type' => 'varchar', 'length' => 255, 'description' => 'salted password, can be null for OpenID users'),
-                 'email' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for password recovery etc.'),
-                 'incomingemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for post-by-email'),
+                 'password' => array('type' => 'varchar', 'length' => 191, 'description' => 'salted password, can be null for OpenID users'),
+                 'email' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for password recovery etc.'),
+                 'incomingemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for post-by-email'),
                  'emailnotifysub' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of subscriptions'),
                  'emailnotifyfav' => array('type' => 'int', 'size' => 'tiny', 'default' => null, 'description' => 'Notify by email of favorites'),
                  'emailnotifynudge' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of nudges'),
@@@ -85,8 -85,8 +85,8 @@@
                  'carrier' => array('type' => 'int', 'description' => 'foreign key to sms_carrier'),
                  'smsnotify' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS'),
                  'smsreplies' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS on replies'),
-                 'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
-                 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+                 'smsemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'built from sms and carrier'),
+                 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
                  'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
                  'subscribe_policy' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => '0 = anybody can subscribe; 1 = require approval'),
                  'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
          return $stream->getNotices($offset, $limit, $since_id, $max_id);
      }
  
 -
 -    function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
 +    public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
      {
 -        // TRANS: Exception thrown when trying view "repeated to me".
 -        throw new Exception(_('Not implemented since inbox change.'));
 +        return $this->getProfile()->repeatedToMe($offset, $limit, $since_id, $max_id);
      }
  
      public static function siteOwner()
diff --combined extlib/DB.php
index b9b5c4a79fdd0462e0a7d0ca4065dd41a42a9364,75ed028c0cbf5ac248b310e1235b8aa06edd4274..adc264287676402433702b8eb23896fb61c11a4a
@@@ -5,7 -5,7 +5,7 @@@
  /**
   * Database independent query interface
   *
 - * PHP versions 4 and 5
 + * PHP version 5
   *
   * LICENSE: This source file is subject to version 3.0 of the PHP license
   * that is available through the world-wide-web at the following URI:
@@@ -20,7 -20,7 +20,7 @@@
   * @author     Daniel Convissor <danielc@php.net>
   * @copyright  1997-2007 The PHP Group
   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 - * @version    CVS: $Id: DB.php,v 1.88 2007/08/12 05:27:25 aharvey Exp $
 + * @version    CVS: $Id$
   * @link       http://pear.php.net/package/DB
   */
  
@@@ -426,12 -426,12 +426,12 @@@ define('DB_PORTABILITY_ALL', 63)
   * @author     Daniel Convissor <danielc@php.net>
   * @copyright  1997-2007 The PHP Group
   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 - * @version    Release: 1.7.13
 + * @version    Release: 1.8.2
   * @link       http://pear.php.net/package/DB
   */
  class DB
  {
 -    // {{{ &factory()
 +    // {{{ factory()
  
      /**
       * Create a new DB object for the specified database type but don't
       *
       * @see DB_common::setOption()
       */
 -    function &factory($type, $options = false)
 +    public static function factory($type, $options = false)
      {
          if (!is_array($options)) {
              $options = array('persistent' => $options);
      }
  
      // }}}
 -    // {{{ &connect()
 +    // {{{ connect()
  
      /**
       * Create a new DB object including a connection to the specified database
       *     'portability' => DB_PORTABILITY_ALL,
       * );
       *
 -     * $db =& DB::connect($dsn, $options);
 +     * $db = DB::connect($dsn, $options);
       * if (PEAR::isError($db)) {
       *     die($db->getMessage());
       * }
       *
       * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError()
       */
 -    function &connect($dsn, $options = array())
 +    public static function connect($dsn, $options = array())
      {
          $dsninfo = DB::parseDSN($dsn);
          $type = $dsninfo['phptype'];
          if (!class_exists($classname)) {
              $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null,
                                      "Unable to include the DB/{$type}.php"
 -                                    . " file for '$dsn'",
 +                                    . " file for '"
 +                                    . DB::getDSNString($dsn, true) . "'",
                                      'DB_Error', true);
              return $tmp;
          }
       */
      function apiVersion()
      {
 -        return '1.7.13';
 +        return '1.8.2';
      }
  
      // }}}
       *
       * @return bool  whether $value is DB_Error object
       */
 -    function isError($value)
 +    public static function isError($value)
      {
 -        return is_a($value, 'DB_Error');
 +        return is_object($value) && is_a($value, 'DB_Error');         
      }
  
      // }}}
       *
       * @return bool  whether $value is a DB_<driver> object
       */
 -    function isConnection($value)
 +    public static function isConnection($value)
      {
          return (is_object($value) &&
                  is_subclass_of($value, 'db_common') &&
       *
       * @return boolean  whether $query is a data manipulation query
       */
 -    function isManip($query)
 +    public static function isManip($query)
      {
          $manips = 'INSERT|UPDATE|DELETE|REPLACE|'
                  . 'CREATE|DROP|'
       * @return string  the error message or false if the error code was
       *                  not recognized
       */
 -    function errorMessage($value)
 +    public static function errorMessage($value)
      {
          static $errorMessages;
          if (!isset($errorMessages)) {
       *  + username: User name for login
       *  + password: Password for login
       */
 -    function parseDSN($dsn)
 +    public static function parseDSN($dsn)
      {
          $parsed = array(
              'phptype'  => false,
       * @param boolean true to hide the password, false to include it
       * @return string
       */
 -    function getDSNString($dsn, $hidePassword) {
 +    public static function getDSNString($dsn, $hidePassword) {
          /* Calling parseDSN will ensure that we have all the array elements
           * defined, and means that we deal with strings and array in the same
           * manner. */
   * @author     Stig Bakken <ssb@php.net>
   * @copyright  1997-2007 The PHP Group
   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 - * @version    Release: 1.7.13
 + * @version    Release: 1.8.2
   * @link       http://pear.php.net/package/DB
   */
  class DB_Error extends PEAR_Error
      function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
                        $level = E_USER_NOTICE, $debuginfo = null)
      {
+         common_debug(var_export($debuginfo,true));
          if (is_int($code)) {
              $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code,
                                $mode, $level, $debuginfo);
   * @author     Stig Bakken <ssb@php.net>
   * @copyright  1997-2007 The PHP Group
   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 - * @version    Release: 1.7.13
 + * @version    Release: 1.8.2
   * @link       http://pear.php.net/package/DB
   */
  class DB_result
   * @author     Stig Bakken <ssb@php.net>
   * @copyright  1997-2007 The PHP Group
   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 - * @version    Release: 1.7.13
 + * @version    Release: 1.8.2
   * @link       http://pear.php.net/package/DB
   * @see        DB_common::setFetchMode()
   */
index 6b82a0fdd12751e0885a5045897b7caaf86d78de,557e50759be04fe4bcc58fcf97132eb508083a03..95c1f6956be5712ab163d02b550408605979a80e
@@@ -51,11 -51,11 +51,11 @@@ class Blog_entry extends Managed_DataOb
  
      public $id; // UUID
      public $profile_id; // int
-     public $title; // varchar(255)
+     public $title; // varchar(191)   not 255 because utf8mb4 takes more space
      public $summary; // text
      public $content; // text
-     public $uri; // text
-     public $url; // text
+     public $uri; // varchar(191)   not 255 because utf8mb4 takes more space
+     public $url; // varchar(191)   not 255 because utf8mb4 takes more space
      public $created; // datetime
      public $modified; // datetime
  
                                        'not null' => true,
                                        'description' => 'Author profile ID'),
                  'title' => array('type' => 'varchar',
-                                  'length' => 255,
+                                  'length' => 191,
                                   'description' => 'title of the entry'),
                  'summary' => array('type' => 'text',
                                     'description' => 'initial summary'),
                  'content' => array('type' => 'text',
                                     'description' => 'HTML content of the entry'),
                  'uri' => array('type' => 'varchar',
-                                'length' => 255,
+                                'length' => 191,
                                 'description' => 'URI (probably http://) for this entry'),
                  'url' => array('type' => 'varchar',
-                                'length' => 255,
+                                'length' => 191,
                                 'description' => 'URL (probably http://) for this entry'),
                  'created' => array('type' => 'datetime',
                                     'not null' => true,
          $be->id         = (string) new UUID();
          $be->profile_id = $profile->id;
          $be->title      = $title; // Note: not HTML-protected
 -        $be->content    = self::purify($content);
 +        $be->content    = common_purify($content);
  
          if (array_key_exists('summary', $options)) {
 -            $be->summary = self::purify($options['summary']);
 +            $be->summary = common_purify($options['summary']);
          } else {
              // Already purified
              $be->summary = self::summarize($be->content);
  
          return $obj;
      }
 -
 -    /**
 -     * Clean up input HTML
 -     */
 -    static function purify($html)
 -    {
 -        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
 -
 -        $config = array('safe' => 1,
 -                        'deny_attribute' => 'id,style,on*');
 -        $pure = htmLawed($html, $config);
 -
 -        return $pure;
 -    }
  }
index 6180d054816023d814eee058ee97ea98aab148f5,959aeef6bd95318fe8c3425485f329aeccd67eef..325e602653664425e7f78d3df9619fbd1c1d2924
@@@ -51,12 -51,12 +51,12 @@@ class Ostatus_profile extends Managed_D
      {
          return array(
              'fields' => array(
-                 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+                 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
                  'profile_id' => array('type' => 'integer'),
                  'group_id' => array('type' => 'integer'),
                  'peopletag_id' => array('type' => 'integer'),
-                 'feeduri' => array('type' => 'varchar', 'length' => 255),
-                 'salmonuri' => array('type' => 'varchar', 'length' => 255),
+                 'feeduri' => array('type' => 'varchar', 'length' => 191),
+                 'salmonuri' => array('type' => 'varchar', 'length' => 191),
                  'avatar' => array('type' => 'text'),
                  'created' => array('type' => 'datetime', 'not null' => true),
                  'modified' => array('type' => 'datetime', 'not null' => true),
  
          // Get (safe!) HTML and text versions of the content
  
 -        $rendered = $this->purify($sourceContent);
 +        $rendered = common_purify($sourceContent);
          $content = common_strip_html($rendered);
  
          $shortened = common_shorten_links($content);
  
          // Get (safe!) HTML and text versions of the content
  
 -        $rendered = $this->purify($sourceContent);
 +        $rendered = common_purify($sourceContent);
          $content = common_strip_html($rendered);
  
          $shortened = common_shorten_links($content);
          return $saved;
      }
  
 -    /**
 -     * Clean up HTML
 -     */
 -    protected function purify($html)
 -    {
 -        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
 -        $config = array('safe' => 1,
 -                        'deny_attribute' => 'id,style,on*');
 -        return htmLawed($html, $config);
 -    }
 -
      /**
       * Filters a list of recipient ID URIs to just those for local delivery.
       * @param Profile local profile of sender
          }
  
          if (!empty($location)) {
-             if (mb_strlen($location) > 255) {
-                 $location = mb_substr($note, 0, 255 - 3) . ' … ';
+             if (mb_strlen($location) > 191) {   // not 255 because utf8mb4 takes more space
+                 $location = mb_substr($note, 0, 191 - 3) . ' … ';
              }
          }
  
                                     'text/html');
  
          $filepath = File::path($filename);
 +        $fileurl = File::url($filename);
  
          file_put_contents($filepath, $final);
  
          $file = new File;
  
          $file->filename = $filename;
 -        $file->url      = File::url($filename);
 +        $file->urlhash  = File::hashurl($fileurl);
 +        $file->url      = $fileurl;
          $file->size     = filesize($filepath);
          $file->date     = time();
          $file->mimetype = 'text/html';