Last active
August 14, 2024 08:21
-
-
Save ronnywang/a427799576047dbc808aaf6bd4b843a6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
include(__DIR__ . '/../init.inc.php'); | |
$request_body = file_get_contents('php://input'); | |
$obj = json_decode($request_body); | |
$db = WedDB::getDb(); | |
foreach ($obj->events as $event) { | |
if (!$userId = $event->source->userId) { | |
file_put_contents(__DIR__ . "/../data/error.jsonl", json_encode(['time' => time(), 'data' => $obj]) . "\n", FILE_APPEND); | |
exit; | |
} | |
$now = time(); | |
$data = null; | |
try { | |
$data = LineAPI::getInfo($userId); | |
} catch (Exception $e) { | |
} | |
$sql = "INSERT INTO line_user " | |
. " (line_id, state, action, user_id, created_at, last_message_at, data) " | |
. " VALUES (:line_id, 0, '', 0, :now, :now, :data) " | |
. " ON DUPLICATE KEY UPDATE last_message_at = :now"; | |
$db->prepare($sql)->execute([ | |
'line_id' => $userId, | |
'now' => $now, | |
'data' => json_encode($data), | |
]); | |
$sql = "SELECT line_user_id, state, action, line_id FROM line_user WHERE line_id = ?"; | |
$stmt = $db->prepare($sql); | |
$stmt->execute([$userId]); | |
$state = $stmt->fetch(PDO::FETCH_ASSOC); | |
$line_user_id = $state['line_user_id']; | |
$sql = "INSERT INTO line_message " | |
. "(line_user_id, created_at, data) " | |
. " VALUES (:line_user_id, :created_at, :data)"; | |
$db->prepare($sql)->execute([ | |
'line_user_id' => $line_user_id, | |
'created_at' => $now, | |
'data' => json_encode($event), | |
]); | |
if ($event->message->type == 'image') { | |
LineAPI::saveContent($event->message->id); | |
} | |
if ($event->message->text == '!彈幕') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => "請輸入你想送出的彈幕,若不想發彈幕,請按「停發彈幕」", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'message', | |
'label' => '停發彈幕', | |
'text' => '!停發彈幕', | |
], | |
], | |
] | |
], | |
]]); | |
$sql = "UPDATE line_user SET action = :action WHERE line_user_id = :line_user_id"; | |
$db->prepare($sql)->execute([ | |
'action' => '彈幕', | |
'line_user_id' => $state['line_user_id'], | |
]); | |
} elseif ($event->message->text == '!停發彈幕') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => "停發成功", | |
]]); | |
$sql = "UPDATE line_user SET action = :action WHERE line_user_id = :line_user_id"; | |
$db->prepare($sql)->execute([ | |
'action' => '停發彈幕', | |
'line_user_id' => $state['line_user_id'], | |
]); | |
continue; | |
} elseif ($event->message->text == '!meettheone') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => "testing", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => 'meettheone', | |
'uri' => 'https://evelyn.ronny.tw/meettheone.php?id=' . $state['line_user_id'] . '&secret=' . crc32($state['line_user_id'] . $state['line_id']), | |
], | |
], | |
], | |
], | |
]]); | |
continue; | |
} elseif ($event->message->text == '!祝福彈幕') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => "您可以選擇送上祝福或是發出彈幕,祝福的話會在畫面上輪播,並且您也可以加上照片,而彈幕則是在送出後直接會在螢幕上顯示,是對現在螢幕上的互動,您可以選擇是祝福還是彈幕再輸入文字喔", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => '祝福', | |
'uri' => 'https://evelyn.ronny.tw/greeting.php?id=' . $state['line_user_id'] . '&secret=' . crc32($state['line_user_id'] . $state['line_id']), | |
], | |
], | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'message', | |
'label' => '彈幕', | |
'text' => '!彈幕', | |
], | |
], | |
], | |
], | |
]]); | |
$sql = "UPDATE line_user SET action = :action WHERE line_user_id = :line_user_id"; | |
$db->prepare($sql)->execute([ | |
'action' => '祝福彈幕', | |
'line_user_id' => $state['line_user_id'], | |
]); | |
continue; | |
} else if ($event->message->text == '!簽到') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [ | |
[ | |
'type' => 'text', | |
'text' => "請輸入您的手機號碼報到" | |
], | |
]); | |
continue; | |
} else if ($event->message->text == '!抖內') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [ | |
[ | |
'type' => 'text', | |
'text' => "請選擇抖內的方式,您可以使用: | |
1.信用卡:點選下面的信用卡連結即可。 | |
2.Line Pay:使用 Line Pay 請直接跟 Ronny 和 Evelyn 連絡,私下透過 Line 付款即可。 | |
3.現場現金付款:畢竟是婚宴,還是可以包紅包的啊 | |
餐費提醒: | |
大人2000元/人,小孩1000元/人", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => ' 信用卡', | |
'uri' => 'https://ronnyevelyn.oen.tw/', | |
], | |
], | |
], | |
], | |
]]); | |
$sql = "UPDATE line_user SET action = :action WHERE line_user_id = :line_user_id"; | |
$db->prepare($sql)->execute([ | |
'action' => '抖內', | |
'line_user_id' => $state['line_user_id'], | |
]); | |
continue; | |
} else if ($event->message->text == '!小遊戲') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [ | |
[ | |
'type' => 'text', | |
'text' => "請選擇要參與的婚禮小遊戲:" | |
], | |
[ | |
'type' => 'text', | |
'text' => "「婚後大小事」的主旨是提供我們維繫婚姻的建議。 | |
在「婚後大小事1:小孩生不生」這個主題,請熱心的朋友提供有關生小孩的建言,以及生與不生的原因。 | |
「婚後大小事2:幸福小秘訣」則是請走在這條路上的朋友們,分享維持婚姻的秘訣和自己的經驗分享。 | |
每個人不僅可以留下自己的看法,也可以瀏覽別人寫的意見並且按讚表示同意喔! | |
獲得最多人按讚的兩位朋友,可以獲得我們準備的精美禮品一份 🎁", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => 'Kahoot', | |
'uri' => 'https://kahoot.it/', | |
], | |
], | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => '婚後大小事1:小孩生不生', | |
'uri' => 'https://app.sli.do/event/7VrFt5QQRFYqGDXuCTvFvA', | |
], | |
], | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => '婚後大小事2:幸福小秘訣', | |
'uri' => 'https://app.sli.do/event/ujMn3N7mpKV7CWQ67MRXiy', | |
], | |
], | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'uri', | |
'label' => 'meettheone', | |
'uri' => 'https://evelyn.ronny.tw/meettheone.php?id=' . $state['line_user_id'] . '&secret=' . crc32($state['line_user_id'] . $state['line_id']), | |
], | |
], | |
], | |
], | |
]]); | |
$sql = "UPDATE line_user SET action = :action WHERE line_user_id = :line_user_id"; | |
$db->prepare($sql)->execute([ | |
'action' => '小遊戲', | |
'line_user_id' => $state['line_user_id'], | |
]); | |
continue; | |
} | |
if ($state['action'] == '彈幕') { | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
$sql = "INSERT INTO danmu (created_at, created_by, message) VALUES " | |
. " (:created_at, :created_by, :message)"; | |
$db->prepare($sql)->execute([ | |
'created_at' => time(), | |
'created_by' => $state['line_user_id'], | |
'message' => $event->message->text, | |
]); | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => "彈幕發送成功,讓想繼續發彈幕可繼續輸入文字,若不想發彈幕,請按「停發彈幕」", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'message', | |
'label' => '停發彈幕', | |
'text' => '!停發彈幕', | |
], | |
], | |
] | |
], | |
]]); | |
} | |
// default | |
if (!$replyToken = $event->replyToken) { | |
continue; | |
} | |
if ($val = WedDB::getInfoByPhone($event->message->text)) { | |
$tables = WedDB::getTables(); | |
$need_pay = 2000 * $val['出席總人數 [出席人數]'] - 1000 * $val['小孩數']; | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => sprintf("%s 你好👋 | |
已為您報到成功, | |
報到人數為 %d 位大人%s,請領取 %d 盒喜餅🎁 | |
%s,您的座位在 %d 號桌:「%s」。 | |
祝你今晚玩得愉快! | |
Have a nice day❤️", | |
$val['你的姓名,或是您想被稱呼的方式?'], | |
intval($val['出席總人數 [出席人數]']) - intval($val['小孩數']), | |
intval($val['小孩數']) ? ",{$val['小孩數']} 位小孩" : '', | |
intval($val['出席總人數 [出席人數]']) - intval($val['小孩數']), | |
$val['已收到禮金'] ? "已收到禮金:{$val['已收到禮金']}" : "酌收餐費 {$need_pay} 元", | |
$val['座位'], | |
$tables[$val['座位']], | |
), | |
], | |
[ | |
'type' => 'image', | |
'originalContentUrl' => 'https://evelyn.ronny.tw/table.png', | |
'previewImageUrl' => 'https://evelyn.ronny.tw/table.png', | |
] | |
]); | |
continue; | |
} | |
LineAPI::replyMessage($state['line_user_id'], $replyToken, [[ | |
'type' => 'text', | |
'text' => '歡迎加入 Ronny & Evelyn 的婚宴 Line 帳號,婚宴將在 318 開始,您可以用此 Line 帳號發彈幕發祝福及傳照片喔!', | |
]]); | |
continue; | |
/* | |
if (is_null(LineAPI::getName($userId))) { | |
$message = $event->message->text; | |
if ($message == '!不是') { | |
LineAPI::replyMessage($userId, [ | |
'type' => 'text', | |
'text' => "請輸入您的姓名喔", | |
]); | |
} elseif ($message == '!是的') { | |
} else { | |
LineAPI::replyMessage($userId, [ | |
'type' => 'text', | |
'text' => "您未設定名稱,請問「{$message}」是您的名字嗎?", | |
'quickReply' => [ | |
'items' => [ | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'message', | |
'label' => '是的', | |
'text' => '!是的', | |
], | |
], | |
[ | |
'type' => 'action', | |
'action' => [ | |
'type' => 'message', | |
'label' => '不是', | |
'text' => '!不是', | |
], | |
], | |
], | |
], | |
]); | |
} | |
} | |
*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
include(__DIR__ . '/config.php'); | |
date_default_timezone_set('Asia/Taipei'); | |
class WedDB | |
{ | |
protected static $pdo = null; | |
public static function getDb() | |
{ | |
if (self::$pdo) { | |
return self::$pdo; | |
} | |
$uri = getenv('DATABASE_URL'); | |
if (!preg_match('#mysql://([^:]*):([^@]*)@([^/]*)/(.*)#', strval($uri), $matches)) { | |
throw new Exception('wrong DATABASE_URL'); | |
} | |
$options = []; | |
$options['host'] = $matches[3]; | |
$options['user'] = $matches[1]; | |
$options['password'] = $matches[2]; | |
$options['dbname'] = $matches[4]; | |
$config = []; | |
foreach ($options as $key => $value) { | |
if (in_array($key, array('host', 'port', 'user', 'password', 'dbname'))) { | |
$config[] = $key . '=' . $value; | |
} | |
} | |
$pdo = new PDO("mysql:" . implode(';', $config), $options['user'], $options['password']); | |
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
self::$pdo = $pdo; | |
return $pdo; | |
} | |
public static function getTables() | |
{ | |
return [ | |
1 => '建中1', | |
2 => 'PIXNET 1', | |
3 => '李慕約', | |
4 => '塔羅事典/摯友', | |
5 => '秀峰高中', | |
6 => '建中2', | |
7 => 'PIXNET 2', | |
8 => '城市科大', | |
9 => '內湖高中', | |
10 => '麗山國小', | |
11 => 'g0v1', | |
12 => 'g0v2', | |
13 => 'g0v3', | |
14 => '輔大敬業1', | |
15 => '輔大敬業2', | |
]; | |
} | |
public static function getInfoByPhone($phone) | |
{ | |
if (!preg_match('#^09\d\d\d\d\d\d\d\d$#', trim($phone))) { | |
return; | |
} | |
$fp = fopen(__DIR__ . "/data/evelyn.csv", 'r'); | |
$columns = fgetcsv($fp); | |
while ($rows = fgetcsv($fp)) { | |
$values = array_combine($columns, $rows); | |
if ($values['手機'] == $phone) { | |
return $values; | |
} | |
} | |
return null; | |
} | |
} | |
class LineAPI | |
{ | |
public static function getName($userId) | |
{ | |
if (!file_exists(__DIR__ . "/data/user-{$userId}.jsonl")) { | |
return null; | |
} | |
$fp = fopen(__DIR__ . "/data/user-{$userId}.jsonl", 'r'); | |
$name = null; | |
while ($line = fgets($fp)) { | |
$obj = json_decode($line); | |
if ($obj->type != 'recv') { | |
continue; | |
} | |
if (!is_null($name) and $obj->data->message->text == '!是的') { | |
return $name; | |
} | |
$name = $obj->data->message->text; | |
} | |
return null; | |
} | |
public static function replyMessage($user_id, $replyToken, $messages, $type = 'auto') | |
{ | |
$db = WedDB::getDb(); | |
$sql = "INSERT INTO sent_message (user_id, sent_at, message) " | |
. " VALUES (:user_id, :sent_at, :message)"; | |
$db->prepare($sql)->execute([ | |
'user_id' => $user_id, | |
'sent_at' => time(), | |
'message' => json_encode($messages, JSON_UNESCAPED_UNICODE), | |
]); | |
$ret = self::post('https://api.line.me/v2/bot/message/reply', [ | |
'replyToken' => $replyToken, | |
'messages' => $messages, | |
]); | |
return $ret; | |
} | |
public static function get($url) | |
{ | |
$curl = curl_init($url); | |
curl_setopt($curl, CURLOPT_HTTPHEADER, [ | |
"Content-Type: application/json", | |
"Authorization: Bearer " . getenv('APIKEY'), | |
]); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
$content = curl_exec($curl); | |
return $content; | |
} | |
public static function post($url, $data) | |
{ | |
$curl = curl_init($url); | |
curl_setopt($curl, CURLOPT_HTTPHEADER, [ | |
"Content-Type: application/json", | |
"Authorization: Bearer " . getenv('APIKEY'), | |
]); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
$content = curl_exec($curl); | |
return json_decode($content); | |
} | |
public static function getInfo($user_id) | |
{ | |
$content = self::get("https://api.line.me/v2/bot/profile/" . $user_id); | |
if (!$ret = json_decode($content)) { | |
throw new Exception("getInfo failed: " . $content); | |
} | |
if (!property_exists($ret, 'displayName')) { | |
throw new Exception("getInfo failed: " . $content); | |
} | |
return $ret; | |
} | |
public static function saveContent($messageId) | |
{ | |
if (!preg_match('#^\d+$#', $messageId)) { | |
return; | |
} | |
$content = LineAPI::get("https://api-data.line.me/v2/bot/message/{$messageId}/content"); | |
file_put_contents(__DIR__ . "/line-data/" . $messageId, $content); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment