التعامل مع EACUTE والشخصيات الخاصة الأخرى باستخدام Oracle و PHP و OCI8
-
23-09-2019 - |
سؤال
مرحبًا ، أحاول تخزين الأسماء في قاعدة بيانات Oracle وإعادتها باستخدام PHP و OCI8.
ومع ذلك ، إذا قمت بإدخال é
مباشرة في قاعدة بيانات Oracle واستخدم OCI8 لإعادتها ، أتلقى للتو ملف e
هل يجب علي تشفير جميع الأحرف الخاصة (بما في ذلك é
) في كيانات HTML (أي: é
) قبل الإدراج في قاعدة البيانات ... أم أنني أفتقد شيئًا؟
شكرًا
تحديث: 1 مارس الساعة 18:40
وجدت هذه الوظيفة:http://www.php.net/manual/en/function.utf8-decode.php#85034
function charset_decode_utf_8($string) {
if(@!ereg("[\200-\237]",$string) && @!ereg("[\241-\377]",$string)) {
return $string;
}
$string = preg_replace("/([\340-\357])([\200-\277])([\200-\277])/e","'&#'.((ord('\\1')-224)*4096 + (ord('\\2')-128)*64 + (ord('\\3')-128)).';'",$string);
$string = preg_replace("/([\300-\337])([\200-\277])/e","'&#'.((ord('\\1')-192)*64+(ord('\\2')-128)).';'",$string);
return $string;
}
يبدو أنه يعمل ، على الرغم من أنه غير متأكد مما إذا كان الحل الأمثل
تحديث: 8 مارس في 15:45
مجموعة أحرف Oracle هي ISO-8859-1.
في PHP أضفت:
putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1");
لإجبار اتصال OCI8 على استخدام مجموعة الأحرف هذه. استرداد é
باستخدام OCI8 من PHP عملت الآن! (إلى عن على varchars
, ، لكن لا CLOBs
يجب أن تفعل utf8_encode
لاستخراجها)
ثم حاولت حفظ البيانات من PHP إلى Oracle ... ولا تعمل .. في مكان ما على طول الطريق من PHP إلى Oracle é
يصبح ?
تحديث: 9 مارس في الساعة 14:47
لذلك الاقتراب. بعد إضافة متغير NLS_LANG ، يقوم بإدراج OCI8 المباشر مع é
يعمل.
المشكلة هي في الواقع على جانب PHP. باستخدام ExtJS Framework ، عند إرسال نموذج ، فإنه يشفره باستخدامه encodeURIComponent
.
لذا é
يتم إرسالها على النحو %C3%A9
ثم إعادة ترميزها é
.
ومع ذلك ، فإن الطول الآن 2 (strlen($my_sent_value) = 2)
وليس 1. وإذا كنت في php أحاول: $ my_sent_value == é
= خاطئة
أعتقد أنه إذا كنت قادرًا على إعادة ترميز كل هذه الشخصيات في PHP مرة أخرى إلى أطوال حجم البايت 1 ثم إدخالها في Oracle ، فيجب أن تعمل.
لا يزال لا حظ رغم ذلك
تحديث: 10 مارس في 11:05
ما زلت أفكر في أنني قريب جدًا (حتى الآن بعيدًا).
putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P9");
يعمل بشكل متقطع للغاية.
لقد قمت بإنشاء برنامج نصي صغير PHP للاختبار:
header('Content-Type: text/plain; charset=ISO-8859-1');
putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P9");
$conn= oci_connect("user", "pass", "DB");
$stmt = oci_parse($conn, "UPDATE temp_tb SET string_field = '|é|'");
oci_execute($stmt, OCI_COMMIT_ON_SUCCESS);
بعد تشغيل هذا مرة واحدة وقم بتسجيل الدخول إلى قاعدة بيانات Oracle مباشرة ، أرى أن String_Field تم ضبطه على |¿|
. من الواضح أنه ليس ما كنت أتوقعه من تجربتي السابقة.
ومع ذلك ، إذا قمت بتحديث صفحة PHP هذه مرتين بسرعة .... لقد نجحت !!!
في أوراكل رأيت بشكل صحيح |é|
.
يبدو أنه ربما لا يتم تعيين متغير البيئة بشكل صحيح أو إرساله في الوقت المناسب للتنفيذ الأول للنص ، ولكنه متاح للتنفيذ الثاني.
تجربتي التالية هي تصدير المتغير إلى بيئة PHP ، ومع ذلك ، أحتاج إلى إعادة تعيين Apache لذلك ... لذلك سنرى ما يحدث ، ونأمل أن يعمل.
المحلول 2
هذا ما انتهى بي الأمر أخيرًا لحل هذه المشكلة:
عدل ملف تعريف الخفي الذي يدير PHP ليكون:
NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
بحيث يستخدم اتصال OCI8 ISO-8859-1.
ثم في تكوين PHP الخاص بي ، قم بتعيين نوع المحتوى الافتراضي إلى ISO-8859-1:
default_charset = "iso-8859-1"
عندما أقوم بإدخال جدول أوراكل عبر OCI8 من PHP ، أفعل:
utf8_decode($my_sent_value)
وعند تلقي البيانات من Oracle ، يجب أن تعمل طباعة المتغير فقط على النحو التالي:
echo $my_received_value
ومع ذلك ، عند إرسال تلك البيانات عبر أياكس ، اضطررت إلى استخدام:
utf8_encode($my_received_value)
نصائح أخرى
أفترض أنك على دراية بهذه الحقائق:
- هناك العديد من مجموعات الأحرف المختلفة: عليك اختيار واحدة ، وبطبيعة الحال ، تعرف أي شخص تستخدمه.
- Oracle قادر تمامًا على تخزين النص بدون كيانات HTML (
é
). يتم استخدام كيانات HTML في ، حسنا ، HTML. أوراكل ليس متصفح ويب ؛-)
يجب أن تعرف أيضًا أن كيانات HTML لا ترتبط بـ Charset معين ؛ على العكس من ذلك ، يتم استخدامها لتمثيل الأحرف في سياق مستقل عن Charset.
أنت تتحدث بشكل غير واضح عن ISO-8859-1 و UTF-8. ما هو charset تريد استخدامه؟ ISO-8859-1 سهل الاستخدام ، لكن لا يمكنه تخزين النص إلا في بعض اللغات اللاتينية (مثل الإسبانية) ويفتقر إلى بعض العربات الشائعة مثل رمز €. يعد استخدام UTF-8 أكثر صعوبة في استخدامه ، لكن يمكنه تخزين جميع الأحرف المحددة بواسطة Consortium Unicode (والتي تشمل كل ما تحتاجه على الإطلاق).
بمجرد اتخاذ القرار ، يجب عليك تكوين Oracle للاحتفاظ بالبيانات في مثل هذا Charset واختيار نوع العمود المناسب. على سبيل المثال ، varchar2 على ما يرام بالنسبة إلى ASCII العادي ، NVARCHAR2 مفيد لـ UTF-8.
إذا لم تتمكن حقًا من تغيير مجموعة الأحرف التي ستستخدمها Oracle ، فماذا عن ترميز BASE64 لترميز بياناتك قبل تخزينها في قاعدة البيانات. وبهذه الطريقة ، يمكنك قبول الشخصيات من أي مجموعة أحرف وتخزينها كـ ISO-8859-1 (لأن BASE64 ستخرج مجموعة فرعية من مجموعة أحرف ASCII والتي تعرّف تمامًا إلى ISO-8859-1). سيؤدي ترميز BASE64 إلى زيادة طول السلسلة بنسبة 37 ٪ في المتوسط
إذا لم يتم عرض بياناتك إلا على أنها HTML ، فيمكنك أيضًا تخزين كيانات HTML كما اقترحت ، ولكن كن على علم بأن كيان واحد يمكن أن يصل إلى 10 أحرف لكل حرف غير مشفر على سبيل المثال ϑ
اضطررت إلى مواجهة هذه المشكلة: يتم تخزين الشخصيات الخاصة الأمريكية اللاتينية على أنها "؟" أو "¿" في قاعدة بيانات Oracle الخاصة بي ... لا يمكنني تغيير NLS_CHARACTER_SET لأننا لسنا أصحاب قاعدة البيانات.
لذلك ، وجدت الحل البديل:
1) رمز ASP.NET قم بإنشاء دالة تقوم بتحويل السلسلة إلى أحرف سداسي عشرية:
public string ConvertirStringAHex(String input)
{
Encoding encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
Byte[] stringBytes = encoding.GetBytes(input);
StringBuilder sbBytes = new StringBuilder(stringBytes.Length);
foreach (byte b in stringBytes)
{
sbBytes.AppendFormat("{0:X2}", b);
}
return sbBytes.ToString();
}
2) تطبيق الوظيفة أعلاه على المتغير الذي تريد تشفيره ، مثل هذا
myVariableHex = ConvertirStringZHex( myVariable );
في أوراكل ، استخدم ما يلي:
PROCEDURE STORE_IN_TABLE( iTEXTO IN VARCHAR2 )
IS
BEGIN
INSERT INTO myTable( SPECIAL_TEXT )
VALUES ( UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW( iTEXTO ));
COMMIT;
END;
بالطبع ، Itexto هي المعلمة Oracle التي تتلقى قيمة "MyVariableHex" من رمز ASP.NET.
آمل أن يساعد ذلك ... إذا كان هناك شيء لتحسين الثابتة والمتنقلة ، فلا تتردد في نشر تعليقاتك.
مصادر:http://www.nullskull.com/faq/834/convert-tring-to-hex--hex-to-string-in-net.aspx https://forums.oracle.com/thread/44799