精華區 > 酷!學園 精華區

使用 PHP 發送 MSN 訊息

(1/23) > >>

twu2:
最近有個自動發送 MSN 訊息的需求, 是在系統有異常時, 希望可以發送 MSN 訊息通知相關人員 (一般還是發 email, 只是, 多數人並不是隨時都在檢查並讀取 email, 並沒有 IM 的即時效果). 我記得在 Study Area 有看過類似的作法, 找到了這一篇文章 , 打算照著做就可以了, 可惜... 怎麼試都不成功.

首先, 裝了 tmsnc 這套軟體, 結果, 似乎是新版本介面改變, 所以不能使用. 就自己抓了舊的版本回來, 結果... 一樣不能使用. 我試著直接去跑 tmsnc, 是可以正確的登入到  MSN 中, 不過... 當我要傳訊息時, 馬上就跳出這個訊息:
--- 代碼: ---Use an Unicode compitable terminal such as rxvt-unicode or uxterm.
--- 程式碼結尾 ---
接著就結束程式了. 問題是... 我是用 PieTTY 連線, 使用 UTF-8 編碼, 應該也算是 unicode 的 terminal 吧. 而且, 傳的訊息只是一些英文字, 怎麼不行呢? 試著把程式的這個地方改成忽略這個錯誤, 結果, 一樣無法正確的把訊息送出. 試了幾次, 就決定放棄這個軟體了. (奇怪, 怎麼別人用都沒問題?)

上網找了一下, 發現了這一個討論 MSN 協定的網站 (雖然好像很久沒更新? 討論區的資料也好像很舊?), 也找到了這個別人寫的 php MSN class, 抓回來自己用了一下, 果然, 在接收到別人傳入的訊息後, 可以把相同的訊息再傳回去.

因為並沒有直接傳送訊息的功能, 所以我就照著網站上頭的協定, 改了一下程式, 在登入之後, 就送出 XFR 指令取得一個新的 SwitchBoard 伺服器, 然後用一個新的連線到 SB 伺服器, 送出 USR 指令後.... 接著就被斷線了 (奇怪... 看別人寫的怎麼都正常?). 多試了幾次, 發現約 5 次會成功一次, 可是接著的 CAL 指令, 又會被斷線 (這個就完全沒成功過).

試了一下午, 找不出原因. 就打算看別人怎麼寫的. 抓了 qmsn (在 debian 中, 如果 session 不是用 /tmp, 會不能用, 不過... 我改掉這個問題後, 還是不能用?), amsn, gaim 等回來看... 沒什麼特別的啊. 怎麼大家都可以做到. 我的程式就做不到? 後來, 加上一堆除錯的訊息, 才發現我在 XFR 指令取得的 CKI 碼後頭, 還有換行字元存在, 所以我送出的指令, 等於多了一組換行字元, 就被伺服器給斷線了 (果然年紀大了, 寫程式的功力退步不少, 這種小問題, 居然花了快一天才發現). 改了之後, 就可以正確的發送訊息了.

原本打算這樣子就弄好了, 結果... 上線一跑, 如果對方有上線, 是可以正確的收到訊息. 但是如果對方沒有上線, 就完全收不到訊息了. 也就是離線訊息是無法正確使用的.

上網再找了一下, 發現了另一個討論 MSN 協定的網站, 這一個網站看起來有持續的更新中,  上頭還有新的 WLM 8.1 所用的 MSNP15 協定. 由於 MSNP13 開始有支援離線訊息. 所以就把我的程式就照 MSNP13 的內容來改. 也加上了 OIM 的支援. 不過, 怎麼試都不成功. 後來看到 MSNP15 中, 對於 OIM 的傳送方式有些更改, 想說會不會之前 MSNP13 的就不能用了呢 (我覺得可能是我那兒又寫錯了吧, 不然... 總不會之前的舊版 MSN 也不能發離線訊息了嗎?) ?

再把程式改成支援 MSNP15. 這次改的就多了...  因為登入的方式由 TWN 改成  SSO, 且 challenge 檢查碼的計算又改的很複雜 (用到一些平常不常用的  mhash, mcrypt, bcmath 等模組, 所以... 如果你要用 OIM 的話, 你使用的 PHP 就必須加上這些模組的支援), 花了快一天才全部改好. 不過... 辛苦是有代價的, 這次果然可以正確的發送出離線訊息了. (該網站上頭對於 OIM 的 XML 內容, 似乎還是舊的, 有些內容和我自己用 WLM 8.1 把除錯功能打開所取得的記錄內容似乎不太一樣, 我是用我由 WLM 中抓到的那個 XML 才能正確傳送 OIM. 也許之前用 MSNP13 無法傳送也是類似的問題, 不過, 我這兒沒有使用 MSNP13 的 WLM 8.0 版本, 所以, 不確定是否是因為這個原因才不能使用)

整理了一下, 我把這個程式放在這兒 (使用 GPL 授權方式):  http://www.teatime.com.tw/~tommy/files/msnclass.7z

你只要寫一個小程式, 就可以用來發送 MSN 訊息了, 如:
--- 代碼: ---#!/usr/bin/php -Cq
<?php

error_reporting&#40;E_ALL&#41;;
include_once&#40;'msn.class.php'&#41;;

// force to use MSNP9, without debug information
// $msn = new MSN&#40;'MSNP9'&#41;;

// force to use MSNP9, with debug information
// $msn = new MSN&#40;'MSNP9', true&#41;;

// force to use MSNP15, without debug information
// $msn = new MSN&#40;'MSNP15'&#41;;

// force to use MSNP15, with debug information
// $msn = new MSN&#40;'MSNP15', true&#41;;

// auto detect MSN protocol, without debug information
// $msn = new MSN;

// auto detect MSN protocol, with debug information
$msn = new MSN&#40;'', true&#41;;

if &#40;!$msn->connect&#40;'YOUR_ID', 'YOUR_PASSWORD'&#41;&#41; &#123;
    echo "Error for connect to MSN network\n";
    echo "$msn->error\n";
    exit;
&#125;

$msn->sendMessage&#40;'Now&#58; '.strftime&#40;'%D %T'&#41;."\nTesting\nSecond Line\n\n\n\nand Empty Line",
                  array&#40;
                    'somebody1@hotmail.com',
                    'somebody2@hotmail.com'
                       &#41;
                 &#41;;
echo "Done!\n";
exit;

?>
--- 程式碼結尾 ---
建議先用 $msn = new MSN('', true) 的方式跑一次, 確定沒有問題後, 再把除錯的功能關閉.

再提醒一次, 你的系統用的 PHP 至少要有 curl, pcre 這兩個模組才能使用 MSNP9. 如果要發送 OIM, 就得使用 MSNP15, 這時, 還要有 mhash, mcrypt, bcmath 等模組才可以.

補充一下, 那個傳送的訊息, 如果不是英文, 請使用 UTF-8 編碼才能正確的傳送. 因為 MSN 在傳送的訊息, 是使用 UTF-8 編碼的.

Darkhero:
太棒了!~...
這篇一定要置頂..
感謝 twu2 大大的貢獻...

sakana:
感謝 twu2大大 ^^
真是獲益良多

twu2:
有了之前用 PHP 寫的 MSN class 之後, 要在一般的 shell script 中來發送 MSN 的訊息就不是件難事了.

首先, 最好每一台機器都去申請一個新的 MSN 帳號 (因為同一個帳號不能同時在兩台機器上登入, 先進去的好像會被後進去的踢出去), 反正申請帳號也不用什麼費用. 當然, 要收這個訊息的帳號, 記得要允許由這個新的帳號發送訊息才可以.

然後, 寫一個小的 php script 如下:
--- 代碼: ---#!/usr/bin/php -Cq
<?php

error_reporting&#40;0&#41;;

if &#40;!isset&#40;$argc&#41;&#41; $argc = $_SERVER['argc'&#93;;
if &#40;!isset&#40;$argv&#41;&#41; $argv = $_SERVER['argv'&#93;;

if &#40;$argc != 3&#41; &#123;
    echo "Syntax&#58; $argv[0&#93; to msg\n";
    exit;
&#125;

$aTo = explode&#40;',', $argv[1&#93;&#41;;
$sMsg = $argv[2&#93;;

$msn_acct = 'YOUR_MSN_ACCOUNT';
$msn_password = 'YOUR_MSN_PASSWORD';

include_once&#40;'msn.class.php'&#41;;

$msn = new MSN;

if &#40;!$msn->connect&#40;$msn_acct, $msn_password&#41;&#41; &#123;
    echo "Error for connect to MSN network\n";
    echo "$msn->error\n";
    exit;
&#125;

$msn->sendMessage&#40;$sMsg, $aTo&#41;;
if &#40;$msn->error != ''&#41;
    echo "Error&#58; $msn->error\n";

exit;

?>
--- 程式碼結尾 ---

上頭的 YOUR_MSN_ACCOUNT, YOUR_MSN_PASSWORD 設好後, 把這個檔案存成 msnsendmsg.php, 連同 msn.class.php 放到 /usr/local/bin 下頭. 記得把 msnsendmsg.php 加上可執行的屬性.

這樣子處理之後, 我們只要執行 msnsendmsg.php, 第一個參數是要接收這個訊息的使用者 (如果有多個, 以逗號分隔), 第二個參數就是要傳送的訊息 (用 UTF-8 編碼).  例如:
--- 代碼: ---#!/bin/sh

msnsendmsg.php "user_a@hotmail.com,user_b@hotmail.com" "Date: $(date)
Subject: Test
=================================================
測試 line 1
line 2
line 3
以下空白


結束
================================================="

exit

--- 程式碼結尾 ---

當然, 要送什麼內容就由你自己決定吧. 這樣子, 是不是很方便呢?

上頭的文章, 同步發表於我的 blog:
http://blog.teatime.com.tw/1/post/200
http://blog.teatime.com.tw/1/post/201

LPJ:
感謝twu2提供!!
並應用於 http://gm5.cc/msn

導覽

[0] 文章列表

[#] 下頁

前往完整版本