Tag Archive อาร์เรย์

MySQL: select ข้อมูลจาก json array

Mysql การดึงข้อมูลจากรูปแบบ json ที่เก็บเป็น array ไว้ จะเขียน query ซับซ้อนกว่าปกตินิดหนึ่งเพราะว่าต้องมีการดึงข้อมูลโดยทราบจำนวนแถว เช่น จากข้อมูล

CREATE TABLE `app_fd_books` (
  `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `dateCreated` datetime DEFAULT NULL,
  `dateModified` datetime DEFAULT NULL,
  `c_books` longtext COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `app_fd_books` (`id`,`dateCreated`,`dateModified`,`c_books`) VALUES ('b04469bd-ac1430f1-12bd2000-a4f7da3a','2018-03-03 22:54:56','2018-03-03 22:54:56','[{\n		\"title\": \"สูญสิ้นความเป็นคน\",\n		\"author\": \"ดะไซ โอซามุ\",\n		\"publisher\": \"JLIT\"\n	}, {\n		\"title\": \"ถอดรหัสรักออนไลน์\",\n		\"author\": \"Aziz Ansari\",\n		\"publisher\": \"openworlds\"\n	},\n	{\n		\"title\": \"เพลงรัตติกาลในอินเดีย\",\n		\"author\": \"Antonio Tabucchi\",\n		\"publisher\": \"อ่านอิตาลี\"\n	},\n	{\n		\"title\": \"อันเดอร์กราวด์\",\n		\"author\": \"ผู้เขียน: ฮารูกิ มูราคามิ\",\n		\"publisher\": \"กำมะหยี่\"\n	},\n	{\n		\"title\": \"ร้านหนังสือเลขที่ 84 ถนนแชริงครอสส์\",\n		\"author\": \"Helene Hanff\",\n		\"publisher\": \"Bookmoby Press\"\n	},\n	{\n		\"title\": \"ปรัชญาในภาพยนตร์\",\n		\"author\": \"ผู้เขียน: สิตางค์ เจริญวงศ์ และ ฐานชน จันทร์เรือง\",\n		\"publisher\": \"ปล่อยสำนักพิมพ์\"\n	},\n	{\n		\"title\": \"ผู้มาเยือนหลังเที่ยงคืน\",\n		\"author\": \"แพทริก เนส\",\n		\"publisher\": \"เวิร์ดส์วอนเดอร์\"\n	},\n	{\n		\"title\": \"เข้าป่าหาชีวิต\",\n		\"author\": \"จอน คราคาวเออร์\",\n		\"publisher\": \"มูลนิธิหนังสือเพื่อสังคม\"\n	},\n	{\n		\"title\": \"ไกลกว่ารั้วบ้านของเรา\",\n		\"author\": \"โรสนี นูรฟารีดา\",\n		\"publisher\": \"ผจญภัย\"\n	},\n	{\n		\"title\": \"สัจนิยมมหัศจรรย์\",\n		\"author\": \"ชูศักดิ์ ภัทรกุลวณิชย์\",\n		\"publisher\": \"อ่าน\"\n	},\n	{\n		\"title\": \"เข้าป่าหาชีวิต\",\n		\"author\": \"จอน คราคาวเออร์\",\n		\"publisher\": \"มูลนิธิหนังสือเพื่อสังคม\"\n	},\n	{\n		\"title\": \"ความลับ 5 ข้อที่คุณต้องค้นให้พบก่อนตาย\",\n		\"author\": \"จอห์น อิซโซ\",\n		\"publisher\": \"โอ้มายก้อด\"\n	},\n	{\n		\"title\": \"ฝนบางหยด กลายเป็นผีเสื้อ\",\n		\"author\": \"ลัดดา สงกระสินธิ์\",\n		\"publisher\": \"สมมติ\"\n	},\n	{\n		\"title\": \"Open Diary\",\n		\"author\": \"วรพจน์ พันธุ์พงศ์\",\n		\"publisher\": \"บางลำพู\"\n	},\n	{\n		\"title\": \"A Gothic Soul\",\n		\"author\": \"Jiří Karásek ze Lvovic\",\n		\"publisher\": \"Twisted Spoon\"\n	},\n	{\n		\"title\": \"ไกลกว่ารั้วบ้านของเรา\",\n		\"author\": \"โรสนี นูรฟารีดา\",\n		\"publisher\": \"ผจญภัย\"\n	},\n	{\n		\"title\": \"ประวัติศาสตร์นับศูนย์: สู่การสูญพันธุ์ครั้งที่ 6\",\n		\"author\": \"เอลิซาเบธ โคลเบิร์ต\",\n		\"publisher\": \"openworlds\"\n	},\n	{\n		\"title\": \"FUTURE : ปัญญาอนาคต\",\n		\"author\": \"ภิญโญ ไตรสุริยธรรมา\",\n		\"publisher\": \"openbooks\"\n	}\n]');

c_books มีจำนวนข้อมูลที่เก็บเอาไว้ 18 รายการ

เพื่อความสดวกการเขียน query จะใช้วิธีสร้างตารางเก็บ index ไว้ให้เกาะโดย เราจะสร้างตาราง integers ที่เก็บจำนวนเต็มตั้งแต่ 0 ถึง n ( function JSON_EXTRACT เริ่มจาก index 0 ) เอาไว้ให้ใช้ง่ายๆ เช่น

CREATE TABLE `integers` (
`row_number` int(4) NOT NULL,
PRIMARY KEY (`row_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO integers (row_number) VALUES ('0') , ('1') , ('2') , ('3') , ('4') , ('5') , ('6') , ('7') , ('8') , ('9') , ('10') , ('11') , ('12') , ('13') , ('14') , ('15') , ('16') , ('17') , ('18') , ('19') , ('20') , ('21') , ('22') , ('23') , ('24') , ('25') , ('26') , ('27') , ('28') , ('29') , ('30') , ('31') , ('32') , ('33') , ('34') , ('35') , ('36') , ('37') , ('38') , ('39') , ('40') , ('41') , ('42') , ('43') , ('44') , ('45') , ('46') , ('47') , ('48') , ('49') , ('50') , ('51') , ('52') , ('53') , ('54') , ('55') , ('56') , ('57') , ('58') , ('59') , ('60') , ('61') , ('62') , ('63') , ('64') , ('65') , ('66') , ('67') , ('68') , ('69') , ('70') , ('71') , ('72') , ('73') , ('74') , ('75') , ('76') , ('77') , ('78') , ('79') , ('80') , ('81') , ('82') , ('83') , ('84') , ('85') , ('86') , ('87') , ('88') , ('89') , ('90') , ('91') , ('92') , ('93') , ('94') , ('95') , ('96') , ('97') , ('98') , ('99') , ('100')

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

AND (SELECT
            TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                            CONCAT('$[', row_number, '].title')))
        FROM
            app_fd_books
        WHERE
            id = 'b04469bd-ac1430f1-12bd2000-a4f7da3a') IS NOT NULL

ตัวอย่าง query ที่เขียนเสร็จแล้ว เช่น

SELECT
    row_number,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].title'))) AS title,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].author'))) AS author,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].publisher'))) AS publisher
FROM
    app_fd_books AS datas,
    (SELECT
        row_number AS row_number
    FROM
        integers) AS length
WHERE
    datas.id = 'b04469bd-ac1430f1-12bd2000-a4f7da3a'
        AND (SELECT
            TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                            CONCAT('$[', row_number, '].title')))
        FROM
            app_fd_books
        WHERE
            id = 'b04469bd-ac1430f1-12bd2000-a4f7da3a') IS NOT NULL
ORDER BY row_number;

แต่เมื่อใช้ไปนานๆ เจอวิธีที่เขียนได้ง่ายกว่าเดิมคือใช้ JSON_LENGTH ก็จะได้รูปแบบ

SELECT
    row_number,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].title'))) AS title,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].author'))) AS author,
    TRIM(BOTH '"' FROM JSON_EXTRACT(datas.c_books,
                CONCAT('$[', row_number, '].publisher'))) AS publisher
FROM
    integers AS i,
    app_fd_books AS datas
WHERE
    datas.id = 'b04469bd-ac1430f1-12bd2000-a4f7da3a'
        AND i.row_number < JSON_LENGTH(datas.c_books)
ORDER BY row_number;

มันง่าย และสั้นกว่าเยอะเลยพิชญ์

PHP: json_encode ไม่มีผลลัพธ์

เจอว่า json_encode มันไม่ return ผลลัพธ์ ออกมาเลยในหน้าเดียวกัน แต่ต่างกันที่ product id ลอง print_r / var_dump ตัว array ที่เข้าไปใน function ก็ปกติดี ไม่ได้มากมาย หรือมีเครื่องหมายพิเศษอะไร ลอง debug ดูถึงเจอว่าถ้าใช้ function json_last_error() มันจะ return เลข 7 กลับมาในหน้าที่มีปัญหา ลองค้นดูรหัส 7 คือ infinity number ลอง unset ตัว key ที่เป็น float(-INF) ดูก็กลับเป็นปกติจริงๆ

รหัสต่างๆ คือ

JSON error codes
Code Constant Meaning Availability
0 JSON_ERROR_NONE No error has occurred  
1 JSON_ERROR_DEPTH The maximum stack depth has been exceeded  
2 JSON_ERROR_STATE_MISMATCH Invalid or malformed JSON  
3 JSON_ERROR_CTRL_CHAR Control character error, possibly incorrectly encoded  
4 JSON_ERROR_SYNTAX Syntax error  
5 JSON_ERROR_UTF8 Malformed UTF-8 characters, possibly incorrectly encoded PHP 5.3.3
6 JSON_ERROR_RECURSION One or more recursive references in the value to be encoded PHP 5.5.0
7 JSON_ERROR_INF_OR_NAN One or moreNANor INFvalues in the value to be encoded PHP 5.5.0
8 JSON_ERROR_UNSUPPORTED_TYPE A value of a type that cannot be encoded was given PHP 5.5.0
9 JSON_ERROR_INVALID_PROPERTY_NAME A property name that cannot be encoded was given PHP 7.0.0
10 JSON_ERROR_UTF16 Malformed UTF-16 characters, possibly incorrectly encoded PHP 7.0.0
<!doctype html>
<html>
   <head>
      <meta charset="utf-8">
      <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
      <title>PHP: json_encode error</title>
      <meta content="Pitt Phunsanit" name="author" />
   </head>
   <body>
      <div class="container">
         <?php
            $datas = [
            	'ininfity' => -9e1000,
            	'title' => 'title',
            ];
            ?>
         <div class="row"><label class="col-md-2" for="">Datas Arrya:</label><textarea class="col-md-10" cols="100" rows="6"><?=var_dump($datas); ?></textarea></div>
         <div class="row"><label class="col-md-2" for="">Json Datas:</label><textarea class="col-md-10" cols="100" rows="6"><?=json_encode($datas); ?></textarea></div>
         <div class="row">
            <label class="col-md-2" for="">Json Error:</label>
            <div class="col-md-10"><?=json_last_error(); ?></div>
         </div>
         <table class="table table-striped">
            <caption><strong>JSON error codes</strong></caption>
            <thead>
               <tr>
                  <th>Code</th>
                  <th>Constant</th>
                  <th>Meaning</th>
                  <th>Availability</th>
               </tr>
            </thead>
            <tbody class="tbody">
               <tr>
                  <td><strong><code><?=JSON_ERROR_NONE; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_NONE</code></strong></td>
                  <td>No error has occurred</td>
                  <td class="empty">&nbsp;</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_DEPTH; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_DEPTH</code></strong></td>
                  <td>The maximum stack depth has been exceeded</td>
                  <td class="empty">&nbsp;</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_STATE_MISMATCH; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_STATE_MISMATCH</code></strong></td>
                  <td>Invalid or malformed JSON</td>
                  <td class="empty">&nbsp;</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_CTRL_CHAR; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_CTRL_CHAR</code></strong></td>
                  <td>Control character error, possibly incorrectly encoded</td>
                  <td class="empty">&nbsp;</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_SYNTAX; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_SYNTAX</code></strong></td>
                  <td>Syntax error</td>
                  <td class="empty">&nbsp;</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_UTF8; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_UTF8</code></strong></td>
                  <td>Malformed UTF-8 characters, possibly incorrectly encoded</td>
                  <td>PHP 5.3.3</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_RECURSION; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_RECURSION</code></strong></td>
                  <td>One or more recursive references in the value to be encoded</td>
                  <td>PHP 5.5.0</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_INF_OR_NAN; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_INF_OR_NAN</code></strong></td>
                  <td>
                     One or more
                     <a class="link" href="http://php.net/manual/de/language.types.float.php#language.types.float.nan" target="_blank"><strong><code>NAN</code></strong></a>
                     or <a class="link" href="http://php.net/manual/de/function.is-infinite.php" target="_blank"><strong><code>INF</code></strong></a>
                     values in the value to be encoded
                  </td>
                  <td>PHP 5.5.0</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_UNSUPPORTED_TYPE; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_UNSUPPORTED_TYPE</code></strong></td>
                  <td>A value of a type that cannot be encoded was given</td>
                  <td>PHP 5.5.0</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_INVALID_PROPERTY_NAME; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_INVALID_PROPERTY_NAME</code></strong></td>
                  <td>A property name that cannot be encoded was given</td>
                  <td>PHP 7.0.0</td>
               </tr>
               <tr>
                  <td><strong><code><?=JSON_ERROR_UTF16; ?></code></strong></td>
                  <td><strong><code>JSON_ERROR_UTF16</code></strong></td>
                  <td>Malformed UTF-16 characters, possibly incorrectly encoded</td>
                  <td>PHP 7.0.0</td>
               </tr>
            </tbody>
         </table>
      </div>
   </body>
</html>

ส่งค่าตัวแปรในเช็กบ็อกซ์โดย jQuery

เขียนระบบ update ข้อมูลโดยใช้ ajax แต่ปัญหาคือ ใน form นี้มันมี input อยู่หลายตัว และเพราะว่าต้องการแค่ input ที่ชื่อ items[] ตัวเดียวเท่านั้น ถ้าส่ง data ไปโดยใช้ jQuery โดยปกติจะส่งค่าไปโดยใช้ .serialize() หรือ .serializeArray() ก็จะส่งตัวแปรอื่นๆ ที่ไม่จำเป็นติดไปด้วย จนทำให้ url ยาวจนเกิน limit ทำให้ต้องหาวิธีส่งไปเฉพาะตัวที่ใช้จริงๆ เท่านั้น

ตัวอย่างการส่งค่าไปในแบบ array

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>checkbox to array</title>
</head>

<body>
    <ul>
        <li>
            <input name="items[]" type="checkbox" value="c1">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c2">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c3">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c4">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c5">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c6">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c7">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c8">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c9">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c10">
        </li>
    </ul>
    <div id="result"></div>
    <button id="sendBtn" type="submit">Send</button>
    <script src="jquery-3.1.1.min.js"></script>
    <script>
    $(function() {

        $('#sendBtn').click(function() {
            var checkboxs = $('input[name="items\\[\\]"]:checked');

            alert('checked ' + checkboxs.length + ' items');

            var values = checkboxs.map(function() {
                    return $(this).val();
                })
                .get();

            var params = {
                "id": 24,
                "items": values,
            };
            $.ajax({
                "data": params,
                "success": function(data) {
                    $('#result').html(data);
                },
                "type": "GET",
                "url": "processing.php",
            });

        });

    });
    </script>
</body>

</html>

ตัวอย่างการส่งค่าไปในแบบ string

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>checkbox to string</title>
</head>

<body>
    <ul>
        <li>
            <input name="items[]" type="checkbox" value="c1">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c2">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c3">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c4">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c5">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c6">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c7">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c8">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c9">
        </li>
        <li>
            <input name="items[]" type="checkbox" value="c10">
        </li>
    </ul>
    <div id="result"></div>
    <button id="sendBtn" type="submit">Send</button>
    <script src="jquery-3.1.1.min.js"></script>
    <script>
    $(function() {

        $('#sendBtn').click(function() {
            var checkboxs = $('input[name="items\\[\\]"]:checked');

            alert('checked ' + checkboxs.length + ' items');

            var values = checkboxs.map(function() {
                    return $(this).val();
                })
                .get()
                .join();

            alert('values = ' + values);

            var encoded = encodeURIComponent(values);

            alert('URL encoded = ' + encoded);

            var decoded = decodeURIComponent(encoded);

            alert('URL decoded = ' + decoded);

            $.ajax({
                "data": 'id=24&items=' + encoded,
                "success": function(data) {
                    $('#result').html(data);
                },
                "type": "GET",
                "url": "processing.php",
            });

        });

    });
    </script>
</body>

</html>

ตัวอย่างการนำค่าไปเขียนเป็น sql query

<dl>
  <dt>method="GET"</dt>
  <dd><?=print_r($_GET, true);?></dd>
  <dt>method="POST"</dt>
  <dd><?=print_r($_POST, true);?></dd>
</dl>
<?php
if (is_array($_REQUEST['items'])) {
    echo '<br>send items by array';
    $where = "WHERE id IN('" . implode("', '", $_REQUEST['items']) . "')";
} else {
    echo '<br>send items by string';
    $where = "WHERE id IN('" . str_replace(',', "', '", $_REQUEST['items']) . "')";
}

$query = "SELECT *
FROM table_name
$where;";

echo '<br>example query = ' . $query;

เลือกใช้การส่งแบบสตริงหรืออาร์เรย์ ก็แล้วแต่ความสดวก ที่ต้องนำไป loop อีกหรือแค่ใช้ในการสร้างเอสคิวแอลคิวรีอย่างเดียว

แบ่งชื่อ นามสกุล คำนำหน้านาม

โจทย์คือการ import ข้อมูลจาก excel เข้าไปเก็บใน database ซึ่งมันก็ไม่ซับซ้อนอะไรถ้าคำนำหน้านาม ชื่อ ชื่อกลาง นามสกุลมันไม่อยู่ในช่องเดียวกัน แต่ในตารางต้องการให้แยกไว้คนละฟิลย์เพื่อความสดวกในการดึงข้อมูล

ดูง่ายๆ แค่ตัดสตริงค์ตามช่องว่างก็น่าจะได้ แต่อย่างชื่อผม นาย พิชญ์ พันธุ์สนิท และชื่อ นาง ธิติมา แอน ประทุมทิพย์ ต่างกันคือ ตัดออกมาได้อาร์เรย์สมาชิก 3 ตัว และ 4 ตัว ก็เขียนเงื่อนไขได้ง่ายๆ ถ้ามี 4 ตัวก็แสดงว่ามี ชื่อกลาง

title = นาย
firstname = พิชญ์
middlename =
lastname = พันธุ์สนิท

และ
title = นาง
firstname = ธิติมา
middlename = แอน
lastname = ประทุมทิพย์

เขียน if (count($temp) == 4) ก็ได้แล้ว

แต่อย่าง ว่าที่ ร.ต.(หญิง) เต็มศิริ วีรสุข ถ้าใช้วิธี

list($title, $firstname, $middlename, lastname) = explode(' ', 'ว่าที่ ร.ต.(หญิง) เต็มศิริ วีรสุข');

แล้วออกมาเป็น

title = ว่าที่
firstname = ร.ต.
middlename = (หญิง)
lastname = เต็มศิริ

คงไม่งาม และบางราชชื่อไม่มีคำนำหน้านาม (hr ผู้น่ารัก)

โชคดีที่มีคำนำหน้านามไม่เยอะเพราะฉะนั้นใช้วิธีใส่ในอาร์เรย์แล้วเอาไป search หาเอาก็ได้

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>แบ่งชื่อ นามสกุล คำนำหน้านาม</title>
</head>
<body>
<?php

$names = [
    'ซาร่า มาลา กุล เลน ณ อยุธยา',
    'นพ.เหรียญทอง แน่นหนา',
    'นักเทคนิคการแพทย์ภาคภูมิ เดชหัสดิน',
    'นางธิติมา แอน ประทุมทิพย์',
    'นายพิชญ์ พันธุ์สนิท',
    'ว่าที่ ร.ต.(หญิง) เต็มศิริ วีรสุข',
];

$titles = [
    'นพ.',
    'นักเทคนิคการแพทย์',
    'นาง',
    'นาย',
    'ว่าที่ ร.ต.(หญิง)',
];

$results = [];
foreach ($names as $no => $name) {

    $temp = str_replace($titles, '<> ', $name);
    $temp = mb_ereg_replace('/\s+/', '\s', $temp);
    $temp = array_values(array_filter(explode(' ', $temp)));

    if ($temp[0] == '<>') {
        $results[$no]['title'] = substr($name, 0, strpos($name, $temp[1]));
    } else {
        $results[$no]['title'] = '';
        array_unshift($temp, '');
    }

    $results[$no]['firstname'] = $temp[1];
    if (count($temp) == 4) {
        $results[$no]['middlename'] = $temp[2];
        $results[$no]['lastname'] = $temp[3];
    } else {
        unset($temp[0], $temp[1]);
        $results[$no]['middlename'] = '';
        $results[$no]['lastname'] = implode(' ', $temp);
    }
}

echo '<pre>', print_r($results, true), '</pre>';
?>
</body>
</html>

ผลลัพธ์ คือ

Array
(
    [0] => Array
        (
            [title] =>
            [firstname] => ซาร่า
            [middlename] =>
            [lastname] => มาลา กุล เลน ณ อยุธยา
        )

    [1] => Array
        (
            [title] => นพ.
            [firstname] => เหรียญทอง
            [middlename] =>
            [lastname] => แน่นหนา
        )

    [2] => Array
        (
            [title] => นักเทคนิคการแพทย์
            [firstname] => ภาคภูมิ
            [middlename] =>
            [lastname] => เดชหัสดิน
        )

    [3] => Array
        (
            [title] => นาง
            [firstname] => ธิติมา
            [middlename] => แอน
            [lastname] => ประทุมทิพย์
        )

    [4] => Array
        (
            [title] => นาย
            [firstname] => พิชญ์
            [middlename] =>
            [lastname] => พันธุ์สนิท
        )

    [5] => Array
        (
            [title] => ว่าที่ ร.ต.(หญิง)
            [firstname] => เต็มศิริ
            [middlename] =>
            [lastname] => วีรสุข
        )

)

อธิบาย

$temp = str_replace($titles, '<> ', $name);

เปลี่ยนคำนำหน้านามเป็นตัวอื่นก่อน

$temp = mb_ereg_replace('/\s+/', '\s', $temp);

เอาสเปซที่มีมากกว่า 1 ตำแหน่งแทนที่ด้วยช่องว่าแค่ 1 ตำแหน่งก็พอ

$temp = array_values(array_filter(explode(' ', $temp)));

แบ่งข้อมูลออกเป็นส่วนๆ โดย array_values(array_filter()) จะทำให้อินเด็กซ์ของอาร์เรย์เป็นไปตามลำดับ

array_unshift($temp, '');

ถ้าไม่มีคำนำหน้านามก็ใส่ให้มัน ลำดับอาร์เรย์จะได้ไม่เคลื่อนไป

$results[$no]['lastname'] = implode(' ', $temp);

เพราะว่าบางคน นามสกุล จะมีช่องว่างจำนวนมาก เช่น มาลา กุล เลน ณ อยุธยา และถ้าแบ่งข้อมูลผิด ผลลัพธ์ที่ได้ก็ไม่น่าเกลียดเท่าไหร่