PHP แสดงสตริงภายในได้อย่างไร


18

UTF8?
UTF16?

สตริงใน PHP ติดตามการเข้ารหัสที่ใช้หรือไม่

ลองดูตัวอย่างสคริปต์นี้ พูดว่าฉันวิ่ง:

$original = "शक्नोम्यत्तुम्";

เกิดอะไรขึ้นจริงหรือ

เห็นได้ชัดว่าฉันคิดว่า$originalจะไม่มีเพียง 7 ตัวอักษร ร่ายมนตร์เหล่านั้นจะต้องถูกแทนด้วยหลายไบต์ที่นั่น

จากนั้นฉันก็:

$converted = mb_convert_encoding ($original , "UTF-8");

จะเกิดอะไรขึ้น$converted? จะ$convertedแตกต่างจาก$originalอย่างไร

มันจะเป็นเพียงลำดับไบต์ที่แน่นอนเหมือนกัน$originalแต่มีการเข้ารหัสที่แตกต่างกันหรือไม่?


1
PHP รุ่นไหน PHP <6 ไม่สามารถจัดการ UTF-8 แบบดั้งเดิมได้ มีแพ็คเกจและวิธีการที่ช่วย / แก้ปัญหานี้ Google สนุกกับ utf-8 และ php จากนั้นเปลี่ยนไปใช้แพลตฟอร์มอื่นแทน PHP :)
Andrew T Finnell

4
PHP <6? ที่จะรวมถึงรุ่นของ PHP ทุกที่เคยออก ...
tdammers

1
นอกจากนี้ PHP สามารถจัดการ UTF-8 ได้ แต่มันไม่มีประเภทข้อมูลเฉพาะดังนั้นคุณต้องระวังสิ่งที่คุณทำ
tdammers

คำตอบ:


22

สตริง PHP เป็นเพียงลำดับของไบต์โดยไม่มีการเข้ารหัสแท็กใด ๆ ค่าสตริงอาจมาจากแหล่งต่าง ๆ : ไคลเอนต์ (ผ่าน HTTP), ฐานข้อมูล, ไฟล์หรือจากตัวอักษรสตริงในซอร์สโค้ดของคุณ PHP อ่านสิ่งเหล่านี้ทั้งหมดเป็นลำดับไบต์และจะไม่แยกข้อมูลการเข้ารหัสใด ๆ

ตราบใดที่แหล่งข้อมูลและปลายทางของคุณใช้การเข้ารหัสแบบเดียวกันสิ่งที่แย่ที่สุดที่สามารถเกิดขึ้นได้คือตำแหน่งสตริงนั้นผิด (ถ้าคุณใช้การเข้ารหัสแบบหลายไบต์) เนื่องจาก PHP จะนับไบต์ไม่ใช่ตัวอักษร

แต่ถ้าการเข้ารหัสไม่ตรงกัน (เช่นคุณเขียนตัวอักษรสตริงในไฟล์ต้นฉบับที่เก็บเป็น UTF-8 แล้วส่งไปยังฐานข้อมูลที่คาดว่าละติน -1), PHP จะไม่ทำการแปลงใด ๆ สำหรับคุณ: มันจะ คัดลอกไบต์มากกว่าดิบอย่างมีความสุข

ทางออก sanest คือ:

  • ตั้งค่าการเข้ารหัสภายในของ PHP เป็น UTF-8
  • บันทึกไฟล์ต้นฉบับทั้งหมดของคุณเป็น UTF-8
  • ใช้ UTF-8 เป็นการเข้ารหัสเอาต์พุตของคุณ (อย่าลืมส่งContent-typeส่วนหัวที่เหมาะสม)
  • ตั้งค่าการเชื่อมต่อฐานข้อมูลเพื่อใช้ UTF-8 ( SET NAMES UTF8ใน MySQL)
  • กำหนดค่าทุกอย่างเป็น UTF-8 ถ้าเป็นไปได้
  • สำหรับสิ่งใดก็ตามที่คุณไม่สามารถควบคุมได้ (เช่นบริการเว็บของบุคคลที่สาม) ตรวจสอบให้แน่ใจว่าคุณรู้การเข้ารหัสและแปลงเป็น UTF-8 โดยเร็วที่สุดและกลับไปที่การเข้ารหัสอื่น ๆ โดยเร็วที่สุด

ทำไมต้อง UTF-8 เนื่องจากสามารถแสดงอักขระ Unicode ทั้งหมดและแทนที่การเข้ารหัสที่มีอยู่ 7 บิตและ 8 บิตที่มีอยู่ทั้งหมดและเนื่องจากเป็นไบนารีที่เข้ากันได้กับ ASCII นั่นคือสตริง ASCII ที่ถูกต้องทุกตัวนั้นยังเป็นสตริง UTF-8 ที่ถูกต้อง (แต่ไม่ใช่ vv .)

ในตัวอย่างของคุณสิ่งที่เกิดขึ้นคือสิ่งนี้

ก่อนอื่นให้คุณบันทึกไฟล์ต้นฉบับของคุณ เครื่องมือแก้ไขข้อความของคุณอาจได้รับการกำหนดค่าให้ใช้ UTF-8 ดังนั้นตัวอักษรสตริงของคุณจึงสิ้นสุดการเข้ารหัส UTF-8 บนดิสก์ PHP อ่านไฟล์นี้แปลสตริงเป็นชุดของไบต์ $originalตอนนี้มีสตริงที่เข้ารหัส UTF-8 จำนวน 7 ตัวอักษรซึ่งเป็นเพียงลำดับไบต์ (แม้ว่าจะมีมากกว่า 7 ไบต์เพราะอักขระแต่ละตัวจะถูกแทนด้วยสองหรือมากกว่า) หากคุณโทรแล้วecho $originalสตริงที่เข้ารหัสจะถูกส่งไปยังไคลเอ็นต์ตามสภาพ ถ้าคุณบอกให้ลูกค้าคาดหวังว่า UTF-8 ทุกอย่างก็ใช้ได้ แต่ถ้าคุณไม่มี PHP ก็ไม่มีทางที่จะบอกความแตกต่างและคุณจะพบกับขยะในเบราว์เซอร์ เป็นการทดลองให้ลองสิ่งนี้:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

strlen เป็นการเข้ารหัส - ผู้ไม่เชื่อเรื่องพระเจ้าและถือว่าการเข้ารหัส 8 บิตความกว้างคงที่นั่นคือหนึ่งไบต์ต่อตัวอักษรดังนั้นมันจะนับไบต์ไม่ใช่ตัวอักษร


ดังนั้นการแปลง $ จะแสดงถึงสตริงเดียวกัน แต่เป็นการเข้ารหัสอื่น ๆ การเข้ารหัสที่แท้จริงซึ่งเป็นที่เก็บ PhP จะแตกต่างกัน
user4951

2
ฉันจะทำซ้ำเพื่อคุณ: PHP เก็บจำนวนไบต์ไม่ใช่ตัวอักษรและไม่รู้เกี่ยวกับการเข้ารหัสเลย (แม้ว่าฟังก์ชั่นห้องสมุดบางอย่างจะทำก็ตาม
tdammers

1
โอ้และมันคือ "PHP" ไม่ใช่ "PhP"
tdammers

2
ถ้าไบต์ดิบมีค่าเท่ากันความแตกต่างระหว่าง $ ดั้งเดิมกับ $ ที่แปลงจะเป็นเท่าไหร่ นั่นคือสิ่งที่ฉันขอ
user4951

2
อ้อนั่นคือสิ่งที่คุณหมายถึง ใช่ไบต์ดิบเปลี่ยนไปตามการแปลงการเข้ารหัส PHP จำการเข้ารหัสไม่ได้ดังนั้นถ้าคุณแปลงสตริงจากพูด utf-8 เป็น latin-1 แล้วจัดการผลลัพธ์เป็น utf-8 คุณจะเห็นผลลัพธ์แปลก ๆ
tdammers
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.