OJS OCS OMP OHS

You are viewing the PKP Support Forum | PKP Home Wiki



Backporting critical bugfixes to 2.0

Are you responsible for making OCS work -- installing, upgrading, migrating or troubleshooting? Do you think you've found a bug? Post in this forum.

Moderators: jmacgreg, michael, John

Forum rules
What to do if you have a technical problem with OCS:

1. Search the forum. You can do this from the Advanced Search Page or from our Google Custom Search, which will search the entire PKP site. If you are encountering an error, we especially recommend searching the forum for said error.

2. Check the FAQ to see if your question or error has already been resolved. Please note that this FAQ is OJS-centric, but most issues are applicable to both platforms.

3. Post a question, but please, only after trying the above two solutions. If it's a workflow or usability question you should probably post to the OCS Conference Support and Discussion subforum; if you have a development question, try the OCS Development subforum.

Backporting critical bugfixes to 2.0

Postby derekp » Tue Mar 18, 2008 10:33 pm

While preparing to launch a conference website on OCS 2.0.0-1, I have encountered several show-stopper bugs during testing. Investigating further, I find that most of these crashes have already been fixed in CVS.

However, I am reluctant to run CVS HEAD on a production system, for various reasons. For one, I don't know for sure whether the database schema has been finalized, and I don't want the headache of manually migrating 2.0.0 data into an unsupported schema, then having to migrate again when OCS 2.1 comes out. Also, the development code has just entered testing for OCS 2.1, which suggests I would encounter a different set of bugs.

Therefore, I'm posting the following patch backporting some critical bugfixes that I have found from CVS to 2.0.0-1. If anyone has more bugfixes that need to be backported, please post them here as well. (To limit the scope of this thread, please stick to backports of critical fixes from CVS only.)

If the OCS team has the resources, it would be nice if you could release an OCS 2.0.1 while we are waiting for OCS 2.1. As it currently stands, OCS 2.0.0-1 is unsuitable for production use, and having a reliable release of the 2.0 branch would be helpful even if a 2.1 release is imminent.

Code: Select all
--- ocs-2.0.0-1/dbscripts/xml/ocs_schema.xml.backport   2008-02-25 11:18:36.000000000 -0800
+++ ocs-2.0.0-1/dbscripts/xml/ocs_schema.xml    2008-03-05 03:03:28.942422000 -0800
@@ -933,7 +933,4 @@
                        <NOTNULL/>
                </field>
-               <field name="type" type="I1">
-                       <NOTNULL/>
-               </field>
                <field name="stage" type="I1">
                        <NOTNULL/>
@@ -1766,7 +1763,4 @@
                </field>
                <field name="original_file_name" type="C2" size="90"/>
-               <field name="type" type="C2" size="40">
-                       <NOTNULL/>
-               </field>
                <field name="date_uploaded" type="T">
                        <NOTNULL/>
@@ -1819,7 +1819,4 @@
                        <AUTOINCREMENT/>
                </field>
-               <field name="key_hash" type="C2" size="40">
-                       <NOTNULL/>
-               </field>
                <field name="date_created" type="T">
                        <NOTNULL/>
--- ocs-2.0.0-1/classes/payment/ocs/OCSPaymentManager.inc.php.backport  2007-05-16 21:26:33.000000000 +0000
+++ ocs-2.0.0-1/classes/payment/ocs/OCSPaymentManager.inc.php   2008-02-27 10:42:32.000000000 +0000
@@ -47,5 +47,5 @@
        }
 
-       function fulfillQueuedPayment(&$queuedPayment) {
+       function fulfillQueuedPayment($queuedPaymentId, &$queuedPayment) {
                if ($queuedPayment) switch ($queuedPayment->getType()) {
                        case QUEUED_PAYMENT_TYPE_REGISTRATION:
@@ -59,5 +59,5 @@
 
                                $queuedPaymentDao =& DAORegistry::getDAO('QueuedPaymentDAO');
-                               $queuedPaymentDao->deleteQueuedPayment($queuedPayment);
+                               $queuedPaymentDao->deleteQueuedPayment($queuedPaymentId);
                                return true;
                }
--- ocs-2.0.0-1/classes/payment/QueuedPaymentDAO.inc.php.backport       2007-05-08 23:16:43.000000000 +0000
+++ ocs-2.0.0-1/classes/payment/QueuedPaymentDAO.inc.php        2008-02-27 10:43:36.000000000 +0000
@@ -93,8 +93,8 @@
        }
 
-       function deleteQueuedPayment(&$queuedPayment) {
+       function deleteQueuedPayment($queuedPaymentId) {
                return $this->update(
                        'DELETE FROM queued_payments WHERE queued_payment_id = ?',
-                       array($queuedPayment->getQueuedPaymentId())
+                       array($queuedPaymentId)
                );
        }
--- ocs-2.0.0-1/classes/payment/PaymentManager.inc.php.backport 2007-05-08 23:16:43.000000000 +0000
+++ ocs-2.0.0-1/classes/payment/PaymentManager.inc.php  2008-02-27 10:41:35.000000000 +0000
@@ -62,5 +62,5 @@
        }
 
-       function fulfillQueuedPayment(&$queuedPayment) {
+       function fulfillQueuedPayment($queuedPaymentId, &$queuedPayment) {
                fatalError('ABSTRACT CLASS');
        }
--- ocs-2.0.0-1/plugins/paymethod/paypal/PayPalPlugin.inc.php.backport  2007-05-08 23:16:44.000000000 +0000
+++ ocs-2.0.0-1/plugins/paymethod/paypal/PayPalPlugin.inc.php   2008-02-27 10:45:51.000000000 +0000
@@ -201,5 +201,5 @@
 
                                                        // Fulfill the queued payment.
-                                                       if ($ocsPaymentManager->fulfillQueuedPayment($queuedPayment)) exit();
+                                                       if ($ocsPaymentManager->fulfillQueuedPayment($queuedPaymentId, $queuedPayment)) exit();
 
                                                        // If we're still here, it means the payment couldn't be fulfilled.
--- ocs-2.0.0-1/pages/presenter/SubmitHandler.inc.php.backport  2007-04-10 13:45:11.000000000 -0700
+++ ocs-2.0.0-1/pages/presenter/SubmitHandler.inc.php   2008-03-04 23:42:42.577046000 -0800
@@ -22,4 +22,23 @@
         */
        function submit($args) {
+               $user =& Request::getUser();
+               $schedConf =& Request::getSchedConf();
+               if ($user && $schedConf && !Validation::isPresenter()) {
+                       // The user is logged in but not a presenter. If
+                       // possible, enroll them as a presenter automatically.
+                       import('schedConf.SchedConfAction');
+                       $schedConfAction =& new SchedConfAction();
+                       if ($schedConfAction->allowRegPresenter($schedConf)) {
+                               $role =& new Role();
+                               $role->setSchedConfId($schedConf->getSchedConfId());
+                               $role->setConferenceId($schedConf->getConferenceId());
+                               $role->setRoleId(ROLE_ID_PRESENTER);
+                               $role->setUserId($user->getUserId());
+
+                               $roleDao =& DAORegistry::getDAO('RoleDAO');
+                               $roleDao->insertRole($role);
+                       }
+               }
+
                parent::validate();
                parent::setupTemplate(true);
--- ocs-2.0.0-1/classes/submission/presenter/PresenterAction.inc.php.backport   2008-03-17 00:03:24.000000000 -0700
+++ ocs-2.0.0-1/classes/submission/presenter/PresenterAction.inc.php    2008-03-17 00:05:43.279134000 -0700
@@ -285,5 +285,5 @@
                        // Check director version
                        $directorFiles = $submission->getDirectorFileRevisions($paper->getCurrentStage());
-                       foreach ($directorFiles as $directorFile) {
+                       if (is_array($directorFiles)) foreach ($directorFiles as $directorFile) {
                                if ($directorFile->getFileId() == $fileId) {
                                        $canDownload = true;
derekp
 
Posts: 16
Joined: Wed Oct 10, 2007 12:45 am
Location: University of British Columbia

Re: Backporting critical bugfixes to 2.0

Postby asmecher » Wed Mar 19, 2008 9:19 am

Hi derekp,

We have a set of patches for common issues in OCS 2.0 that we're using for installations we host; if you like, PM me and I can provide them. This is effectively a semi-official OCS 2.0.2 -- and it doesn't involve any database schema changes, so you won't have any upgrade problems. (It's been longer than we expected between releases, but the forthcoming OCS 2.1 should set this straight.)

Regards,
Alec Smecher
Public Knowledge Project Team
asmecher
 
Posts: 8857
Joined: Wed Aug 10, 2005 12:56 pm

Re: Backporting critical bugfixes to 2.0

Postby derekp » Thu Mar 20, 2008 12:03 pm

Thanks, Alec, for the patch set. I have cleaned up the patches a little to apply cleanly to OCS 2.0.0-1. Here they are...

Patch 2932 (in which I have fixed a few more calls to canAdminister()):
Code: Select all
--- ocs-2.0.0-1/classes/security/Validation.inc.php.usermgmt    2007-05-15 13:31:08.000000000 -0700
+++ ocs-2.0.0-1/classes/security/Validation.inc.php     2008-03-20 11:38:22.552944000 -0700
@@ -332,5 +332,5 @@
         * @return boolean
         */
-       function canAdminister($conferenceId, $schedConfId, $userId) {
+       function canAdminister($conferenceId, $userId) {

                if (Validation::isSiteAdmin()) return true;
--- ocs-2.0.0-1/pages/manager/PeopleHandler.inc.php.usermgmt    2007-05-16 12:24:25.000000000 -0700
+++ ocs-2.0.0-1/pages/manager/PeopleHandler.inc.php     2008-03-20 11:39:34.141496000 -0700
@@ -356,5 +356,5 @@
                $templateMgr = &TemplateManager::getManager();

-               if (!Validation::canAdminister($conference->getConferenceId(), $schedConfId, $userId)) {
+               if (!Validation::canAdminister($conference->getConferenceId(), $userId)) {
                        // We don't have administrative rights
                        // over this user. Display an error.
@@ -379,5 +379,5 @@
         * Allow the Conference Manager to merge user accounts, including attributed papers etc.
         */
-       /*function mergeUsers($args) {
+       function mergeUsers($args) {                 parent::validate();
                parent::setupTemplate(true);
@@ -447,22 +447,4 @@
                        }

-                       $copyeditorSubmissionDao =& DAORegistry::getDAO('CopyeditorSubmissionDAO');
-                       $copyeditorSubmissions =& $copyeditorSubmissionDao->getCopyeditorSubmissionsByCopyeditorId($oldUserId);
-                       while ($copyeditorSubmission =& $copyeditorSubmissions->next()) {
-                               $copyeditorSubmission->setCopyeditorId($newUserId);
-                               $copyeditorSubmissionDao->updateCopyeditorSubmission($copyeditorSubmission);
-                               unset($copyeditorSubmission);
-                       }
-
-                       $proofreaderSubmissionDao =& DAORegistry::getDAO('ProofreaderSubmissionDAO');
-                       $proofreaderSubmissions =& $proofreaderSubmissionDao->getSubmissions($oldUserId);
-                       while ($proofreaderSubmission =& $proofreaderSubmissions->next()) {
-                               $proofAssignment =& $proofreaderSubmission->getProofAssignment();
-                               $proofAssignment->setProofreaderId($newUserId);
-                               $proofreaderSubmissionDao->updateSubmission($proofreaderSubmission);
-                               unset($proofAssignment);
-                               unset($proofreaderSubmission);
-                       }
-
                        $paperEmailLogDao =& DAORegistry::getDAO('PaperEmailLogDAO');
                        $paperEmailLogDao->transferPaperLogEntries($oldUserId, $newUserId);
@@ -484,5 +466,5 @@
                        $sessionDao->deleteSessionsByUserId($oldUserId);
                        $registrationDao =& DAORegistry::getDAO('RegistrationDAO');
-                       $registrationDao->deleteRegistrantsByUserId($oldUserId);
+                       $registrationDao->deleteRegistrationsByUserId($oldUserId);
                        $temporaryFileDao =& DAORegistry::getDAO('TemporaryFileDAO');
                        $temporaryFileDao->deleteTemporaryFilesByUserId($oldUserId);
@@ -573,5 +555,5 @@
                $templateMgr->assign('roleSymbolic', $roleSymbolic);
                $templateMgr->display('manager/people/selectMergeUser.tpl');
-       }*/
+       }

        /**
@@ -594,5 +576,5 @@

                if ($userId != null && $userId != $user->getUserId()) {
-                       if (!Validation::canAdminister($conference->getConferenceId(), $schedConfId, $userId)) {
+                       if (!Validation::canAdminister($conference->getConferenceId(), $userId)) {
                                // We don't have administrative rights
                                // over this user. Display an error.
@@ -675,5 +657,5 @@
                        $schedConfId = null;

-               if (!empty($userId) && !Validation::canAdminister($conference->getConferenceId(), $schedConfId, $userId)) {
+               if (!empty($userId) && !Validation::canAdminister($conference->getConferenceId(), $userId)) {
                        // We don't have administrative rights
                        // over this user. Display an error.
@@ -784,5 +766,5 @@
                                $schedConfId = null;

-                       if (!Validation::canAdminister($conference->getConferenceId(), $schedConfId, $userId)) {
+                       if (!Validation::canAdminister($conference->getConferenceId(), $userId)) {
                                // We don't have administrative rights
                                // over this user. Display an error.
--- ocs-2.0.0-1/templates/manager/people/selectMergeUser.tpl.usermgmt   2007-04-10 13:45:13.000000000 -0700
+++ ocs-2.0.0-1/templates/manager/people/selectMergeUser.tpl    2008-03-20 11:38:22.699944000 -0700
@@ -80,12 +80,10 @@
                </td>
                <td align="right">
-                       {if $thisUser->getUserId() != $user->getUserId()}
-                               {if $oldUserId != ''}
-                                       {if $oldUserId != $user->getUserId()}
-                                               <a href="#" onclick="confirmAction('{url oldUserId=$oldUserId newUserId=$user->getUserId()}', '{translate|escape:"htmlall" key="manager.people.mergeUsers.confirm" oldUsername=$oldUsername newUsername=$user->getUsername()}')" class="action">{translate key="manager.people.mergeUser"}</a>
-                                       {/if}
-                               {else}
-                                       <a href="{url oldUserId=$user->getUserId()}" class="action">{translate key="manager.people.mergeUser"}</a>
+                       {if $oldUserId != ''}
+                               {if $oldUserId != $user->getUserId()}
+                                       <a href="#" onclick="confirmAction('{url oldUserId=$oldUserId newUserId=$user->getUserId()}', '{translate|escape:"htmlall" key="manager.people.mergeUsers.confirm" oldUsername=$oldUsername newUsername=$user->getUsername()}')" class="action">{translate key="manager.people.mergeUser"}</a>
                                {/if}
+                       {elseif $thisUser->getUserId() != $user->getUserId()}
+                               <a href="{url oldUserId=$user->getUserId()}" class="action">{translate key="manager.people.mergeUser"}</a>
                        {/if}
                </td>


Patch 3010:
Code: Select all
--- ocs-2.0.0-1/plugins/paymethod/paypal/PayPalPlugin.inc.php   2007-09-20 18:02:40
+++ ocs-2.0.0-1/plugins/paymethod/paypal/PayPalPlugin.inc.php   2007-09-26 18:06:50
@@ -249,5 +249,5 @@
                                break;
                        case 'return':
-                               echo 'RETURN';exit();
+                               Request::redirect(null, null, 'index');
                                break;
                }


Patch 3072:
Code: Select all
--- ocs-2.0.0-1/classes/mail/MailTemplate.inc.php       2007-04-10 13:45:07.000000000 -0700
+++ ocs-2.0.0-1/classes/mail/MailTemplate.inc.php       2007-10-15 12:58:01.000000000 -0700
@@ -76,7 +76,7 @@
                        if (!empty($userSig)) $userSig = "\n" . $userSig;
                }

-               if (isset($emailTemplate) && Request::getUserVar('subject')==null && Request::getUserVar('body')==null) {
+               if (isset($emailTemplate) && (Request::getUserVar('subject')==null || Request::getUserVar('body')==null)) {
                        $this->setSubject($emailTemplate->getSubject());
                        $this->setBody($emailTemplate->getBody() . $userSig);
                        $this->enabled = $emailTemplate->getEnabled();


Patch 3089:
Code: Select all
--- ocs-2.0.0-1/classes/form/Form.inc.php.transcode     2007-05-10 20:20:45.000000000 -0700
+++ ocs-2.0.0-1/classes/form/Form.inc.php       2008-03-20 11:01:11.162982000 -0700
@@ -11,5 +11,5 @@
  * Class defining basic operations for handling HTML forms.
  *
- * $Id: Form.inc.php,v 1.6 2007/05/11 03:20:45 mj Exp $
+ * $Id: Form.inc.php,v 1.10 2007/06/08 15:59:59 mj Exp $
  */

@@ -89,23 +89,6 @@
        function setData($key, $value) {

-               if (is_string($value)) {
+               if (is_string($value)) $value = Core::cleanVar($value);

-                       // check for Windows-1252 encoding, and transliterate if necessary
-                       if ($value === utf8_decode($value) && $value !== utf8_encode($value)) {
-                               // string is cp1252
-                               // transliterate cp1252->utf8 to work in utf-8
-                               // utf8_decode to work in latin-1 (information may be lost)
-                               import('core.Transcoder');
-                               $trans =& new Transcoder('CP1252', 'UTF-8');
-                               $value = $trans->trans($value);
-
-                       } elseif ($value !== utf8_decode($value) && $value !== utf8_encode($value)) {
-                               // string is not within utf-8(?)
-                               // normalize to ASCII (lowest common encoding) - information will be lost
-                               import('core.Transcoder');
-                               $trans =& new Transcoder('UTF-8', 'ASCII');
-                               $value = $trans->trans($value);
-                       }
-               }
                $this->_data[$key] = $value;
        }
--- ocs-2.0.0-1/classes/core/Core.inc.php.transcode     2007-04-10 13:45:06.000000000 -0700
+++ ocs-2.0.0-1/classes/core/Core.inc.php       2008-03-20 11:01:11.178977000 -0700
@@ -38,6 +38,22 @@
         * @return string
         */
-       function cleanVar($var, $stripHtml = false) {
-               return $stripHtml ? htmlspecialchars(trim($var), ENT_NOQUOTES, Config::getVar('i18n', 'client_charset')) : trim($var);
+       function cleanVar($var) {
+               // normalize existing HTML special characters to ASCII
+               $var = strtr(trim($var), array("&amp;" => "&", "&quot" => '"', "&lt;" => "<", "&gt;" => ">"));
+
+               // only process strings that are not UTF-8 already
+               if ( !String::isUTF8($var) && Config::getVar('i18n', 'charset_normalization') == 'On' ) {
+                       import('core.Transcoder');
+
+                       // convert string to HTML entities (numeric and named)
+                       $trans =& new Transcoder('CP1252', 'HTML-ENTITIES');
+                       $var = $trans->trans($var);
+
+                       // convert UTF-8 entities back to UTF-8 characters
+                       $trans =& new Transcoder('HTML-ENTITIES', 'UTF-8');
+                       $var = $trans->trans($var);
+               }
+
+               return $var;
        }

--- ocs-2.0.0-1/classes/core/String.inc.php.transcode   2007-04-17 09:27:48.000000000 -0700
+++ ocs-2.0.0-1/classes/core/String.inc.php     2008-03-20 11:01:11.243990000 -0700
@@ -288,6 +288,40 @@

        /**
+        * Detect whether a string contains non-ascii multibyte sequences in the UTF-8 range
+        * Does not require any multibyte PHP libraries
+        * @param $input string input string
+        * @return boolean
+        */
+       function isUTF8 ($str) {
+               // From http://w3.org/International/questions/qa-forms-utf-8.html
+               return preg_match('%(?:
+                               [\xC2-\xDF][\x80-\xBF]                                                          # non-overlong 2-byte
+                               |\xE0[\xA0-\xBF][\x80-\xBF]                                     # excluding overlongs
+                               |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}              # straight 3-byte
+                               |\xED[\x80-\x9F][\x80-\xBF]                                     # excluding surrogates
+                               |\xF0[\x90-\xBF][\x80-\xBF]{2}                          # planes 1-3
+                               |[\xF1-\xF3][\x80-\xBF]{3}                                              # planes 4-15
+                               |\xF4[\x80-\x8F][\x80-\xBF]{2}                          # plane 16
+                               )+%xs', $str);
+       }
+
+       /**
+        * Returns the UTF-8 string corresponding to the unicode value
+        * Does not require any multibyte PHP libraries
+        * (from php.net, courtesy - romans@void.lv)
+        * @param $input string input string
+        * @return boolean
+        */
+       function code2utf ($num) {
+               if ($num < 128) return chr($num);
+               if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
+               if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
+               if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
+               return '';
+       }
+
+       /**
         * Convert UTF-8 encoded characters in a string to escaped HTML entities
-        * This is a helper function for transcoding HTML (perhaps move to core?)
+        * This is a helper function for transcoding into HTML
         * @param $input string input string
         * @return string
@@ -297,33 +331,33 @@
                $max = strlen($str);
                $last = 0;  // keeps the index of the last regular character
-
-   for ($i=0; $i<$max; $i++) {
-       $c = $str{$i};
-       $c1 = ord($c);
-       if ($c1>>5 == 6) {  // 110x xxxx, 110 prefix for 2 bytes unicode
-           $ret .= substr($str, $last, $i-$last); // append all the regular characters we've passed
-           $c1 &= 31; // remove the 3 bit two bytes prefix
-           $c2 = ord($str{++$i}); // the next byte
-           $c2 &= 63;  // remove the 2 bit trailing byte prefix
-           $c2 |= (($c1 & 3) << 6); // last 2 bits of c1 become first 2 of c2
-           $c1 >>= 2; // c1 shifts 2 to the right
-           $ret .= "&#" . ($c1 * 0x100 + $c2) . ";"; // this is the fastest string concatenation
-           $last = $i+1;
-       }
-       elseif ($c1>>4 == 14) {  // 1110 xxxx, 110 prefix for 3 bytes unicode
-           $ret .= substr($str, $last, $i-$last); // append all the regular characters we've passed
-           $c2 = ord($str{++$i}); // the next byte
-           $c3 = ord($str{++$i}); // the third byte
-           $c1 &= 15; // remove the 4 bit three bytes prefix
-           $c2 &= 63;  // remove the 2 bit trailing byte prefix
-           $c3 &= 63;  // remove the 2 bit trailing byte prefix
-           $c3 |= (($c2 & 3) << 6); // last 2 bits of c2 become first 2 of c3
-           $c2 >>=2; //c2 shifts 2 to the right
-           $c2 |= (($c1 & 15) << 4); // last 4 bits of c1 become first 4 of c2
-           $c1 >>= 4; // c1 shifts 4 to the right
-           $ret .= '&#' . (($c1 * 0x10000) + ($c2 * 0x100) + $c3) . ';'; // this is the fastest string concatenation
-           $last = $i+1;
-       }
-   }
+
+               for ($i=0; $i<$max; $i++) {
+                       $c = $str{$i};
+                       $c1 = ord($c);
+                       if ($c1>>5 == 6) {                                                                              // 110x xxxx, 110 prefix for 2 bytes unicode
+                               $ret .= substr($str, $last, $i-$last);                  // append all the regular characters we've passed
+                               $c1 &= 31;                                                                                                      // remove the 3 bit two bytes prefix
+                               $c2 = ord($str{++$i});                                                          // the next byte
+                               $c2 &= 63;                                                                                                      // remove the 2 bit trailing byte prefix
+                               $c2 |= (($c1 & 3) << 6);                                                        // last 2 bits of c1 become first 2 of c2
+                               $c1 >>= 2;                                                                                                      // c1 shifts 2 to the right
+                               $ret .= "&#" . ($c1 * 0x100 + $c2) . ";";       // this is the fastest string concatenation
+                               $last = $i+1;
+                       }
+                       elseif ($c1>>4 == 14) {                                                                 // 1110 xxxx, 110 prefix for 3 bytes unicode
+                               $ret .= substr($str, $last, $i-$last);                  // append all the regular characters we've passed
+                               $c2 = ord($str{++$i});                                                          // the next byte
+                               $c3 = ord($str{++$i});                                                          // the third byte
+                               $c1 &= 15;                                                                                              // remove the 4 bit three bytes prefix
+                               $c2 &= 63;                                                                                              // remove the 2 bit trailing byte prefix
+                               $c3 &= 63;                                                                                              // remove the 2 bit trailing byte prefix
+                               $c3 |= (($c2 & 3) << 6);                                                        // last 2 bits of c2 become first 2 of c3
+                               $c2 >>=2;                                                                                                       //c2 shifts 2 to the right
+                               $c2 |= (($c1 & 15) << 4);                                                       // last 4 bits of c1 become first 4 of c2
+                               $c1 >>= 4;                                                                                              // c1 shifts 4 to the right
+                               $ret .= '&#' . (($c1 * 0x10000) + ($c2 * 0x100) + $c3) . ';'; // this is the fastest string concatenation
+                               $last = $i+1;
+                       }
+               }
                $str=$ret . substr($str, $last, $i); // append the last batch of regular characters

@@ -331,4 +365,207 @@
        }

+       /**
+        * Convert numeric HTML entities in a string to UTF-8 encoded characters
+        * This is a native alternative to the buggy html_entity_decode() using UTF8
+        * @param $input string input string
+        * @return string
+        */
+       function html2utf($str) {
+               // convert named entities to numeric entities
+               $str = strtr($str, String::getHTMLEntities());
+
+               // use PCRE-aware replace function to replace numeric entities
+               $str = String::regexp_replace('~&#x([0-9a-f]+);~ei', 'String::code2utf(hexdec("\\1"))', $str);
+               $str = String::regexp_replace('~&#([0-9]+);~e', 'String::code2utf(\\1)', $str);
+
+               return $str;
+        }
+
+       /**
+        * Convert UTF-8 numeric entities in a string to ASCII values
+        * This is a helper function for transcoding into HTML/XML
+        * @param $input string input string
+        * @return string
+        */
+       function html2ascii ($str) {
+               // define the conversion table
+               $entities = array(
+                       "&#126;" => "~",                        "&#160;" => " ",                                "&#161;" => "!",
+                       "&#166;" => "|",                                "&#177;" => "+/-",              "&#178;" => "2",
+                       "&#179;" => "3",                        "&#180;" => "'",                                "&#185;" => "1",
+                       "&#188;" => "1/4",              "&#189;" => "1/2",              "&#190;" => "3/4",
+                       "&#191;" => "?",                                "&#192;" => "A",                        "&#193;" => "A",
+                       "&#194;" => "A",                        "&#195;" => "A",                        "&#196;" => "A",
+                       "&#197;" => "A",                        "&#198;" => "AE",                       "&#199;" => "C",
+                       "&#200;" => "E",                        "&#201;" => "E",                        "&#202;" => "E",
+                       "&#203;" => "E",                        "&#204;" => "I",                                "&#205;" => "I",
+                       "&#206;" => "I",                                "&#207;" => "I",                                "&#208;" => "D",
+                       "&#209;" => "N",                        "&#210;" => "O",                        "&#211;" => "O",
+                       "&#212;" => "O",                        "&#213;" => "O",                        "&#214;" => "O",
+                       "&#215;" => "x",                        "&#216;" => "O",                        "&#217;" => "U",
+                       "&#218;" => "U",                        "&#220;" => "U",                        "&#221;" => "Y",
+                       "&#224;" => "a",                        "&#225;" => "a",                        "&#226;" => "a",
+                       "&#227;" => "a",                        "&#228;" => "a",                        "&#229;" => "a",
+                       "&#230;" => "ae",                       "&#231;" => "c",                                "&#232;" => "e",
+                       "&#233;" => "e",                        "&#234;" => "e",                        "&#235;" => "e",
+                       "&#236;" => "i",                                "&#237;" => "i",                                "&#238;" => "i",
+                       "&#239;" => "i",                                "&#240;" => "o",                        "&#241;" => "n",
+                       "&#242;" => "o",                        "&#243;" => "o",                        "&#244;" => "o",
+                       "&#245;" => "o",                        "&#246;" => "o",                        "&#248;" => "o",
+                       "&#249;" => "u",                        "&#250;" => "u",                        "&#252;" => "u",
+                       "&#253;" => "y",                                "&#255;" => "y",                                "&#338;" => "OE",
+                       "&#339;" => "oe",                       "&#352;" => "S",                        "&#353;" => "s",
+                       "&#376;" => "Y",                        "&#39;" => "'",                         "&#402;" => "f",
+                       "&#45;" => "-",                         "&#710;" => "^",                        "&#732;" => "~",
+                       "&#8194;" => " ",                       "&#8195;" => " ",                       "&#8201;" => " ",
+                       "&#8211;" => "-",                       "&#8212;" => "--",              "&#8216;" => "'",
+                       "&#8217;" => "'",                       "&#8218;" => ",",                       "&#8220;" => '"',
+                       "&#8221;" => '"',                       "&#8222;" => ",,",                      "&#8226;" => "*",
+                       "&#8230;" => "...",                     "&#8240;" => "%o",              "&#8242;" => "'",
+                       "&#8243;" => "''",                      "&#8482;" => "TM",              "&#8722;" => "-",
+                       "&#8727;" => "*",                       "&#8743;" => "/\\",             "&#8744;" => "\/",
+                       "&#8764;" => "~",                       "&#8901;" => "*",                       "&#913;" => "A",
+                       "&#914;" => "B",                        "&#917;" => "E",                        "&#918;" => "Z",
+                       "&#919;" => "H",                        "&#921;" => "|",                                "&#922;" => "K",
+                       "&#924;" => "M",                        "&#925;" => "N",                        "&#927;" => "O",
+                       "&#929;" => "P",                        "&#932;" => "T",                        "&#933;" => "Y",
+                       "&#935;" => "X",                        "&#94;" => "^",                         "&#959;" => "o",
+                       "&#961;" => "p",                        "&#962;" => "?",                                "&#977;" => "?",
+                       "&#982;" => "?");
+
+               return strtr($str, $entities);
+       }
+
+       /**
+        * Convert Windows CP-1252 numeric entities in a string to named HTML entities
+        * This is a helper function for transcoding into HTML/XML
+        * @param $input string input string
+        * @return string
+        */
+       function cp1252ToEntities ($str) {
+               // define the conversion table;  from: http://www.noqta.it/tc.html
+               $cp1252 = array(        "&#128;" => "",                                         "&#129;" => "",
+                                                                               "&#130;" => "&lsquor;",         "&#131;" => "&fnof;",
+                                                                               "&#132;" => "&ldquor;",         "&#133;" => "&hellip;",
+                                                                               "&#134;" => "&dagger;",         "&#135;" => "&Dagger;",
+                                                                               "&#136;" => "",                                         "&#137;" => "&permil;",
+                                                                               "&#138;" => "&Scaron;",         "&#139;" => "&lsaquo;",
+                                                                               "&#140;" => "&OElig;",                  "&#141;" => "",
+                                                                               "&#142;" => "",                                         "&#143;" => "",
+                                                                               "&#144;" => "",                                         "&#145;" => "&lsquo;",
+                                                                               "&#146;" => "&rsquo;",                  "&#147;" => "&ldquo;",
+                                                                               "&#148;" => "&rdquo;",          "&#149;" => "&bull;",
+                                                                               "&#150;" => "&ndash;",          "&#151;" => "&mdash;",
+                                                                               "&#152;" => "&tilde;",                  "&#153;" => "&trade;",
+                                                                               "&#154;" => "&scaron;",         "&#155;" => "&rsaquo;",
+                                                                               "&#156;" => "&oelig;",                  "&#157;" => "",
+                                                                               "&#158;" => "",                                         "&#159;" => "&Yuml;");
+
+               // corrections to map to valid ISO entities
+               $cp1252["&#130;"] = "&lsquo;";
+               $cp1252["&#132;"] = "&ldquo;";
+               $cp1252["&#146;"] = "&rsquo;";
+               $cp1252["&#148;"] = "&rdquo;";
+
+               return strtr($str, $cp1252);
+       }
+
+       /**
+        * Return an associative array of named->numeric HTML entities
+        * Required to support HTML functions without objects in PHP4/PHP5
+        * From php.net: function.get-html-translation-table.php
+        * @return string
+        */
+       function getHTMLEntities () {
+               // define the conversion table
+               $html_entities = array(
+                       "&Aacute;" => "&#193;",                 "&aacute;" => "&#225;",                 "&Acirc;" => "&#194;",
+                       "&acirc;" => "&#226;",                          "&acute;" => "&#180;",                          "&AElig;" => "&#198;",
+                       "&aelig;" => "&#230;",                          "&Agrave;" => "&#192;",                 "&agrave;" => "&#224;",
+                       "&alefsym;" => "&#8501;",               "&Alpha;" => "&#913;",                          "&alpha;" => "&#945;",
+                       "&amp;" => "&#38;",                                     "&and;" => "&#8743;",                           "&ang;" => "&#8736;",
+                       "&apos;" => "&#39;",                                    "&Aring;" => "&#197;",                          "&aring;" => "&#229;",
+                       "&asymp;" => "&#8776;",                 "&Atilde;" => "&#195;",                         "&atilde;" => "&#227;",
+                       "&Auml;" => "&#196;",                           "&auml;" => "&#228;",                           "&bdquo;" => "&#8222;",
+                       "&Beta;" => "&#914;",                           "&beta;" => "&#946;",                           "&brvbar;" => "&#166;",
+                       "&bull;" => "&#8226;",                          "&cap;" => "&#8745;",                           "&Ccedil;" => "&#199;",
+                       "&ccedil;" => "&#231;",                         "&cedil;" => "&#184;",                          "&cent;" => "&#162;",
+                       "&Chi;" => "&#935;",                                    "&chi;" => "&#967;",                                    "&circ;" => "&#94;",
+                       "&clubs;" => "&#9827;",                 "&cong;" => "&#8773;",                  "&copy;" => "&#169;",
+                       "&crarr;" => "&#8629;",                 "&cup;" => "&#8746;",                           "&curren;" => "&#164;",
+                       "&dagger;" => "&#8224;",                "&Dagger;" => "&#8225;",                "&darr;" => "&#8595;",
+                       "&dArr;" => "&#8659;",                          "&deg;" => "&#176;",                            "&Delta;" => "&#916;",
+                       "&delta;" => "&#948;",                          "&diams;" => "&#9830;",                 "&divide;" => "&#247;",
+                       "&Eacute;" => "&#201;",                 "&eacute;" => "&#233;",                 "&Ecirc;" => "&#202;",
+                       "&ecirc;" => "&#234;",                          "&Egrave;" => "&#200;",                 "&egrave;" => "&#232;",
+                       "&empty;" => "&#8709;",                 "&emsp;" => "&#8195;",                  "&ensp;" => "&#8194;",
+                       "&Epsilon;" => "&#917;",                        "&epsilon;" => "&#949;",                        "&equiv;" => "&#8801;",
+                       "&Eta;" => "&#919;",                                    "&eta;" => "&#951;",                                    "&ETH;" => "&#208;",
+                       "&eth;" => "&#240;",                                    "&Euml;" => "&#203;",                           "&euml;" => "&#235;",
+                       "&euro;" => "&#8364;",                          "&exist;" => "&#8707;",                 "&fnof;" => "&#402;",
+                       "&forall;" => "&#8704;",                        "&frac12;" => "&#189;",                 "&frac14;" => "&#188;",
+                       "&frac34;" => "&#190;",                 "&frasl;" => "&#8260;",                         "&Gamma;" => "&#915;",
+                       "&gamma;" => "&#947;",                  "&ge;" => "&#8805;",                            "&gt;" => "&#62;",
+                       "&harr;" => "&#8596;",                          "&hArr;" => "&#8660;",                          "&hearts;" => "&#9829;",
+                       "&hellip;" => "&#8230;",                        "&Iacute;" => "&#205;",                         "&iacute;" => "&#237;",
+                       "&Icirc;" => "&#206;",                          "&icirc;" => "&#238;",                          "&iexcl;" => "&#161;",
+                       "&Igrave;" => "&#204;",                 "&igrave;" => "&#236;",                 "&image;" => "&#8465;",
+                       "&infin;" => "&#8734;",                         "&int;" => "&#8747;",                           "&Iota;" => "&#921;",
+                       "&iota;" => "&#953;",                           "&iquest;" => "&#191;",                 "&isin;" => "&#8712;",
+                       "&Iuml;" => "&#207;",                           "&iuml;" => "&#239;",                           "&Kappa;" => "&#922;",
+                       "&kappa;" => "&#954;",                  "&Lambda;" => "&#923;",                 "&lambda;" => "&#955;",
+                       "&lang;" => "&#9001;",                          "&laquo;" => "&#171;",                          "&larr;" => "&#8592;",
+                       "&lArr;" => "&#8656;",                          "&lceil;" => "&#8968;",
+                       "&ldquo;" => "&#8220;",                 "&le;" => "&#8804;",                                    "&lfloor;" => "&#8970;",
+                       "&lowast;" => "&#8727;",                        "&loz;" => "&#9674;",                           "&lrm;" => "&#8206;",
+                       "&lsaquo;" => "&#8249;",                        "&lsquo;" => "&#8216;",                 "&lt;" => "&#60;",
+                       "&macr;" => "&#175;",                           "&mdash;" => "&#8212;",                 "&micro;" => "&#181;",
+                       "&middot;" => "&#183;",                 "&minus;" => "&#45;",                           "&Mu;" => "&#924;",
+                       "&mu;" => "&#956;",                                     "&nabla;" => "&#8711;",                 "&nbsp;" => "&#160;",
+                       "&ndash;" => "&#8211;",                 "&ne;" => "&#8800;",                            "&ni;" => "&#8715;",
+                       "&not;" => "&#172;",                                    "&notin;" => "&#8713;",                 "&nsub;" => "&#8836;",
+                       "&Ntilde;" => "&#209;",                         "&ntilde;" => "&#241;",                         "&Nu;" => "&#925;",
+                       "&nu;" => "&#957;",                                     "&Oacute;" => "&#211;",                 "&oacute;" => "&#243;",
+                       "&Ocirc;" => "&#212;",                          "&ocirc;" => "&#244;",                          "&OElig;" => "&#338;",
+                       "&oelig;" => "&#339;",                          "&Ograve;" => "&#210;",                 "&ograve;" => "&#242;",
+                       "&oline;" => "&#8254;",                 "&Omega;" => "&#937;",                  "&omega;" => "&#969;",
+                       "&Omicron;" => "&#927;",                "&omicron;" => "&#959;",                        "&oplus;" => "&#8853;",
+                       "&or;" => "&#8744;",                                    "&ordf;" => "&#170;",                           "&ordm;" => "&#186;",
+                       "&Oslash;" => "&#216;",                 "&oslash;" => "&#248;",                 "&Otilde;" => "&#213;",
+                       "&otilde;" => "&#245;",                         "&otimes;" => "&#8855;",                        "&Ouml;" => "&#214;",
+                       "&ouml;" => "&#246;",                           "&para;" => "&#182;",                           "&part;" => "&#8706;",
+                       "&permil;" => "&#8240;",                        "&perp;" => "&#8869;",                          "&Phi;" => "&#934;",
+                       "&phi;" => "&#966;",                                    "&Pi;" => "&#928;",                                     "&pi;" => "&#960;",
+                       "&piv;" => "&#982;",                                    "&plusmn;" => "&#177;",                 "&pound;" => "&#163;",
+                       "&prime;" => "&#8242;",                 "&Prime;" => "&#8243;",                 "&prod;" => "&#8719;",
+                       "&prop;" => "&#8733;",                  "&Psi;" => "&#936;",                                    "&psi;" => "&#968;",
+                       "&quot;" => "&#34;",                                    "&radic;" => "&#8730;",                 "&rang;" => "&#9002;",
+                       "&raquo;" => "&#187;",                          "&rarr;" => "&#8594;",                          "&rArr;" => "&#8658;",
+                       "&rceil;" => "&#8969;",                         "&rdquo;" => "&#8221;",                 "&real;" => "&#8476;",
+                       "&reg;" => "&#174;",                                    "&rfloor;" => "&#8971;",                        "&Rho;" => "&#929;",
+                       "&rho;" => "&#961;",                                    "&rlm;" => "&#8207;",                           "&rsaquo;" => "&#8250;",
+                       "&rsquo;" => "&#8217;",                 "&sbquo;" => "&#8218;",                 "&Scaron;" => "&#352;",
+                       "&scaron;" => "&#353;",                 "&sdot;" => "&#8901;",                          "&sect;" => "&#167;",
+                       "&shy;" => "&#173;",                                    "&Sigma;" => "&#931;",                  "&sigma;" => "&#963;",
+                       "&sigmaf;" => "&#962;",                 "&sim;" => "&#8764;",                           "&spades;" => "&#9824;",
+                       "&sub;" => "&#8834;",                           "&sube;" => "&#8838;",                  "&sum;" => "&#8721;",
+                       "&sup1;" => "&#185;",                           "&sup2;" => "&#178;",                           "&sup3;" => "&#179;",
+                       "&sup;" => "&#8835;",                           "&supe;" => "&#8839;",                  "&szlig;" => "&#223;",
+                       "&Tau;" => "&#932;",                            "&tau;" => "&#964;",                                    "&there4;" => "&#8756;",
+                       "&Theta;" => "&#920;",                          "&theta;" => "&#952;",                          "&thetasym;" => "&#977;",
+                       "&thinsp;" => "&#8201;",                        "&THORN;" => "&#222;",                  "&thorn;" => "&#254;",
+                       "&tilde;" => "&#126;",                          "&times;" => "&#215;",                          "&trade;" => "&#8482;",
+                       "&Uacute;" => "&#218;",                 "&uacute;" => "&#250;",                 "&uarr;" => "&#8593;",
+                       "&uArr;" => "&#8657;",                          "&Ucirc;" => "&#219;",                          "&ucirc;" => "&#251;",
+                       "&Ugrave;" => "&#217;",                 "&ugrave;" => "&#249;",                 "&uml;" => "&#168;",
+                       "&upsih;" => "&#978;",                          "&Upsilon;" => "&#933;",                        "&upsilon;" => "&#965;",
+                       "&Uuml;" => "&#220;",                           "&uuml;" => "&#252;",                           "&weierp;" => "&#8472;",
+                       "&Xi;" => "&#926;",                                     "&xi;" => "&#958;",                                     "&Yacute;" => "&#221;",
+                       "&yacute;" => "&#253;",                 "&yen;" => "&#165;",                                    "&yuml;" => "&#255;",
+                       "&Yuml;" => "&#376;",                           "&Zeta;" => "&#918;",                           "&zeta;" => "&#950;",
+                       "&zwj;" => "&#8205;",                           "&zwnj;" => "&#8204;");
+
+               return $html_entities;
+       }
 }

--- ocs-2.0.0-1/classes/core/Transcoder.inc.php.transcode       2007-05-10 11:53:47.000000000 -0700
+++ ocs-2.0.0-1/classes/core/Transcoder.inc.php 2008-03-20 11:01:11.282978000 -0700
@@ -17,18 +17,64 @@
        var $fromEncoding;
        var $toEncoding;
+       var $translit;

-       function Transcoder($fromEncoding, $toEncoding) {
+       function Transcoder($fromEncoding, $toEncoding, $translit = false) {
                $this->fromEncoding = $fromEncoding;
                $this->toEncoding = $toEncoding;
+               $this->translit = $translit;
        }

        function trans($string) {
-               if (function_exists('iconv')) {
+               // detect existence of encoding conversion libraries
+               $mbstring = function_exists('mb_convert_encoding');
+               $iconv = function_exists('iconv');
+
+               // ===  special cases for HTML entities to handle various PHP platforms
+               // 'HTML-ENTITIES' is not a valid encoding for iconv, so transcode manually
+
+               if ($this->toEncoding == 'HTML-ENTITIES' && !$mbstring) {
+
+                       if ( strtoupper($this->fromEncoding) == 'UTF-8' ) {
+                               return String::utf2html($string);               // NB: this will return all numeric entities
+                       } else {
+                               // NB: old PHP versions may have issues with htmlentities()
+                               if ($string == html_entity_decode($string, ENT_COMPAT, $this->fromEncoding)) {
+                                       return htmlentities($string, ENT_COMPAT, $this->fromEncoding);
+                               } else {
+                                       return $string;
+                               }
+                       }
+
+               } elseif ($this->fromEncoding == 'HTML-ENTITIES' && !$mbstring) {
+
+                       if ( strtoupper($this->toEncoding) == 'UTF-8' ) {
+                               // use built-in transcoding to UTF8
+                               return String::html2utf($string);
+
+                       } else {
+                               // NB: old PHP versions may have issues with html_entity_decode()
+                               return html_entity_decode($string, ENT_COMPAT, $this->toEncoding);
+                       }
+
+               // === end special cases for HTML entities
+
+               } elseif ($this->translit == true && $iconv) {
                        // use the iconv library to transliterate
                        return iconv($this->fromEncoding, $this->toEncoding . '//TRANSLIT', $string);

-               } elseif (function_exists('mb_convert_encoding')) {
-                       // fall back to using the multibyte library if necessary (no transliteration)
-                       return mb_convert_encoding($string, $this->toEncoding, $this->fromEncoding);
+               } elseif ($this->translit == true && $this->fromEncoding == "UTF-8" && $this->toEncoding == "ASCII") {
+                       // transliterate using built-in mapping
+                       return String::html2utf(String::html2ascii(String::utf2html($string)));
+
+               // === end special cases for transliteration
+
+               } elseif ($mbstring) {
+                       // use the multibyte library to transcode (no transliteration)
+                       // this call semantic uses backwards-compatible by-reference for better reliability
+                       return call_user_func_array('mb_convert_encoding', array(&$string, $this->toEncoding, $this->fromEncoding));
+
+               } elseif ($iconv) {
+                       // use the iconv library to transcode
+                       return iconv($this->fromEncoding, $this->toEncoding . '//IGNORE', $string);

                } else {
--- ocs-2.0.0-1/config.TEMPLATE.inc.php.transcode       2007-05-16 15:11:01.000000000 -0700
+++ ocs-2.0.0-1/config.TEMPLATE.inc.php 2008-03-20 11:01:11.404948000 -0700
@@ -132,4 +132,8 @@
 database_charset = Off

+; Enable character normalization to utf-8 (recommended)
+; If disabled, strings will be passed through in their native encoding
+charset_normalization = On
+
 ; Default time zone
 ; default_timezone =
derekp
 
Posts: 16
Joined: Wed Oct 10, 2007 12:45 am
Location: University of British Columbia


Return to OCS Technical Support

Who is online

Users browsing this forum: No registered users and 3 guests