歡迎您光臨本站 註冊首頁

使用 PHP 在站點上構建類似 Twitter 的系統

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  

學習如何使用 PHP 為應用程序添加類似 Twitter 的界面。具體來講,我們將展示如何允許用戶發貼,將貼子轉發給希望接收的其他用戶,以及允許用戶選擇追隨其他用戶的貼子。

如果您曾經留意過,就會知道 Twitter 是 Web 2.0 世界最大的轟動事件之一。簡單來說,Twitter(Twitter.com 上提供的一個服務)是一個簡單的微博客服務,用戶可以發最多 140 個字元的貼子(稱作 tweet),回答 “你現在在做什麼?” 之類的問題。用戶可以追隨他們感興趣的人,也有自己的追隨者。通過這種方式,可以將信息發布給追隨者或是廣泛地轉發。

隨意瀏覽一下某個 Twitter 賬戶可以發現,用戶常常發布關於很多不同話題的 tweet,從日常生活(例如 “我在吃三明治”)到更不平凡的話題。其中常常嵌入了圖像、媒體文件和日誌的鏈接。這些 URL 常常被 TinyURL 之類的服務縮短,主要是為了使貼子的總字元數不超過 140 個字元。

很多人喜歡上了 Twitter,使超短格式成了一種藝術形式,甚至將之用於與其他用戶交談(例如將他們的評論定向到 @user)。從這個簡單的起點開始,湧現了大量支持 Twitter 的移動應用程序和其他工具。現在甚至還有專門為最有趣、最卓越和最詳實的 tweet 而設置的獎項,另外還有跟蹤不同 Twitter 應用程序的狀態的在線應用程序。

很多其他站點和服務,例如 LinkedIn 和 Facebook 現在允許用戶用仿照 Twitter 的方式更新他們的當前狀態。換句話說,在 Facebook 更新狀態需要使用短消息,當然,狀態通常是回答 “你現在在幹什麼” 之類的問題。

為您自己的站點添加微博客或狀態更新工具不需要做很多工作,但是卻可以為用戶帶來樂趣和簡單的交流方式。本文的目標是展示如何實現這個目的。但是,首先需要對您作一些假設。

首先,假設您對 PHP 和 MySQL 有所了解。同時假設您可以訪問某個運行 PHP 和 MySQL 的本地 Apache Web 伺服器。對於本文,我在使用 Macintosh、Apache、MySQL 和 PHP(MAMP)的 MacBook Products 上進行開發,這個免費程序將整個開發環境打包到一個包中。但是,您應該能夠毫無困難地在 Microsoft® Windows® 或 Linux® 上進行開發。最後,假設您已經有一個可以立即運行的應用程序,該應用程序現在有一些用戶,您打算以某種方式將微博客或 tweeting 添加到該應用程序中。為此,我簡化應用程序中側重用戶的一些方面(例如登錄、管理個人文件等),而側重於貼子。

設計應用程序的後端

簡言之,Twitter 服務以兩個名詞為中心:用戶和消息。如果您已經構建了一個應用程序,並且希望將類似 Twitter 的服務添加到應用程序中,那麼很可能已經有了用戶管理功能。如果還沒有,那麼需要採用某種方式使用一個資料庫表(一個主鍵,通常是一個整數)、一個用戶名(也是惟一的)、一個電子郵件地址和密碼等標識每個用戶。

tweet(即貼子)存儲在一個 posts 表中,每個貼子有一個主鍵(某種連續整數)、一個指向發出該貼的用戶的外鍵關係、貼子本身(限制為一定數量的字元)和日期/時間戳。

最容易令人感到迷惑的是顯示用戶追隨關係的資料庫表。這裡需要某種方式記錄用戶 ID 和追隨者 ID,使應用程序能夠快速建立追隨者列表,並輕鬆地將信息轉發給那些已註冊為要追隨某用戶的其他用戶。

理解這些內容后,現在就可以著手建立這 3 個資料庫表。使用清單 1 中的 SQL 代碼創建第一個表,即 users 表(如果已經有一個 users 表,則可以跳過這一步)。


清單 1. users 表

CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 255 ) NOT NULL ,
`email` VARCHAR( 255 ) NOT NULL ,
`password` VARCHAR( 8 ) NOT NULL ,
`status` ENUM( 'active', 'inactive' ) NOT NULL
) ENGINE = MYISAM ;




下面是第二個表,即 posts 表。


清單 2. posts 表

CREATE TABLE `posts` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`body` VARCHAR( 140 ) NOT NULL ,
`stamp` DATETIME NOT NULL
) ENGINE = MYISAM ;



清單 3 顯示了最後一個表,即 following 表。注意這個表有兩個主鍵。


清單 3. following 表

CREATE TABLE `following` (
`user_id` INT NOT NULL ,
`follower_id` INT NOT NULL ,
PRIMARY KEY ( `user_id` , `follower_id` )
) ENGINE = MYISAM ;



然後,先創建一個名為 header.php 的文件,將所有用於 MySQL 的連接字元串放到該文件中。如果已經有一個這樣的文件,可以跳過這一步。請務必在各處都包括這個文件,因為將來需要用到它。清單 4 展示了這個文件的內容。


清單 4. 樣例 header.php 文件

$SERVER = 'localhost';
$USER = 'username';
$PASS = 'password';
$DATABASE = 'microblogger';


if (!($mylink = mysql_connect( $SERVER, $USER, $PASS))){
echo "<h3>Sorry, could not connect to database.</h3><br/>
Please contact your system's admin for more help\n";
exit;
}

mysql_select_db( $DATABASE );



請記住,還可以隨意將任何其他類型的安全檢查添加到這個 header.php 文件中。例如,可以檢查一個會話變數中是否設置了一個用戶 ID(表明該用戶已經登錄)。如果用戶沒有登錄,那麼可以將用戶重定向到登錄頁面。本文不會深入討論這一點,不過需要時可以很容易地添加安全檢查。







創建輸入表單

設置好後端表之後,就可以考慮處理數據插入和更新的 PHP。現在需要的是一些簡單的函數,這些函數將:

允許用戶登錄和添加貼子。
將那些貼子轉發給追隨那個用戶的人。
允許用戶追隨其他用戶。
我通常在模型-視圖-控制器(Model-View-Controller,MVC)應用程序框架(例如 CodeIgniter)的上下文中工作,因為它提供了一套工具用於創建這些類型的應用程序。例如,我一般先創建兩個模型(一個用於用戶,另一個用於貼子),這兩個模型使我可以與 users、posts 和 following 表交互,然後從這兩個模型開始繼續前進。

由於您可能已經在使用不同的框架,所以我決定在此不使用上述方法。相反,我選擇一種更簡單的、獨立於框架的方法。對於本文,我們走走捷徑,直接將記錄添加到 users 表中,以創建一系列測試用戶,供應用程序使用。我創建 3 個用戶,並將他們的用戶名設為 jane、 tommy 和 bill。

然後,創建一個簡單的名為 functions.php 的 PHP 文件,該文件將包含主要的功能。在該文件中要創建少量的函數,以支持微博客應用程序上下文中的動作。

如清單 5 所示,第一個函數是一個簡單的函數,用於將內容添加到 posts 表中。


清單 5. 用於將內容添加到 posts 表中的函數

function add_post($userid,$body){
$sql = "insert into posts (user_id, body, stamp)
values ($userid, '". mysql_real_escape_string($body). "',now())";

$result = mysql_query($sql);
}



為了測試這個簡單的函數,還需要添加另外兩個 PHP 文件。一個是 index.php 文件,目前包含一個基本的小表單 — 後面將向頁面添加更多內容。另一個 PHP 文件是 add.php,上述表單將被發布到該文件。清單 6 是 index.php 文件的摘錄。請注意,在此使用一個 PHP 會話將一個用戶 ID 值硬編碼為 1,這是我的資料庫中的用戶 jane。現在這樣做完全沒有問題,但是在後面顯然需要更改。


清單 6. index.php 文件摘錄

<?php
session_start();
include_once('header.php');
include_once('functions.php');

$_SESSION['userid'] = 1;
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Microblogging Application</title>
</head>
vbody>

<?php
if (isset($_SESSION['message'])){
echo "<b>". $_SESSION['message']."</b>";
unset($_SESSION['message']);
}
?>
<form method='post' action='add.php'>
<p>Your status:</p>
<textarea name='body' rows='5' cols='40' wrap=VIRTUAL></textarea>
<p><input type='submit' value='submit'/></p>
</form>

</body>
</html>



此外還應注意,我在表單上為狀態消息留下了空間,這將在 add.php 中動態地設置,如下面的清單所示。


清單 7. 用 add.php 文件將貼子添加到資料庫中

<?php
session_start();
include_once("header.php");
include_once("functions.php");

$userid = $_SESSION['userid'];
$body = substr($_POST['body'],0,140);

add_post($userid,$body);
$_SESSION['message'] = "Your post has been added!";

header("Location:index.php");
?>



上述代碼應該沒有什麼特別令人奇怪的東西。它只是接受表單的 body 欄位和 PHP 會話中設置的 user ID,然後將它們傳遞給 functions.php 文件中的 add_post() 函數。然後,設置另一個會話變數(更新消息),並將用戶重定向回 index.php 頁面。

如果要測試這個小函數,惟一的方法是檢查資料庫中的 posts 表。這不太符合用戶友好性,不是嗎?這裡需要的是更新主頁上的貼子。為此,需要再將一個函數添加到 functions.php 文件中,並在主頁上使用它。







添加一系列的更新

現在可以打開 functions.php 文件並在其中添??另一個函數。這一次,將函數命名為 show_posts()。它將顯示特定用戶 ID 的所有貼子,如下面的清單所示。


清單 8. show_posts() 函數

function show_posts($userid){
$posts = array();

$sql = "select body, stamp from posts
where user_id = '$userid' order by stamp desc";
$result = mysql_query($sql);

while($data = mysql_fetch_object($result)){
$posts[] = array( 'stamp' => $data->stamp,
'userid' => $userid,
'body' => $data->body
);
}
return $posts;

}



如果為這個函數傳遞一個用戶 ID,它將在一個多維數組中按日期倒序的順序返回那個用戶發出的貼子。要使用該函數,只需在 index.php 上調用它,並檢索那個用戶的所有貼子。由於對於每個記錄只需處理少量的數據,這種查詢可以很好地進行擴展。

清單 9 是添加到 index.php 頁面的代碼,這些代碼就放在前面添加的表單之後。通過使用 show_posts() 函數和會話變數,可以獲得登錄的用戶發出的所有貼子。如果沒有貼子,則顯示某種錯誤消息。如果有貼子,則在一個表中逐個顯示它們 — 或者,如果想別緻一點,可以使用自己的級聯樣式表(CSS)。


清單 9. 在 index.php 頁面上顯示貼子

<?php
$posts = show_posts($_SESSION['userid']);

if (count($posts)){
?>
<table border='1' cellspacing='0' cellpadding='5' width='500'>
<?php
foreach ($posts as $key => $list){
echo "<tr valign='top'>\n";
echo "<td>".$list['userid'] ."</td>\n";
echo "<td>".$list['body'] ."<br/>\n";
echo "<small>".$list['stamp'] ."</small></td>\n";
echo "</tr>\n";
}
?>
</table>
<?php
}else{
?>
<p><b>You haven't posted anything yet!</b></p>
<?php
}
?>



圖 1 顯示到目前為止的基本界面 — 還不錯,幾分鐘就有這樣的成績。


圖 1. 基本界面



容易的部分就完成了。現在有了一個基本的應用程序,用戶可以發布狀態,並看到它在頁面上顯示。但是,還缺少一個重要的部分:除了發布狀態的人以外,沒有人看到狀態更新。在下一節中,將創建一個簡單的界面,其中列出系統中的所有用戶,並且允許已登錄的用戶追隨其他用戶並看到他們的狀態更新。







追隨其他用戶

接下來可以將更多東西添加到 functions.php 文件中。這裡需要一個 show_users() 函數,該函數可以返回系統中所有用戶的一個列表。後面將使用這個函數填充一個用戶列表。


清單 10. show_users() 函數

function show_users(){
$users = array();
$sql = "select id, username from users where status='active' order by username";
$result = mysql_query($sql);

while ($data = mysql_fetch_object($result)){
$users[$data->id] = $data->username;
}
return $users;
}



有了 show_users() 函數之後,接下來可以創建一個 users.php 文件,該文件將運行這個函數,並顯示系統中所有用戶的一個列表,對於每個用戶,在用戶名的旁邊都有一個 follow 鏈接。


清單 11. 運行 show_users() 函數的 users.php 文件

<?php
session_start();
include_once("header.php");
include_once("functions.php");

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Microblogging Application - Users</title>
</head>
<body>

<h1>List of Users</h1>
<?php
$users = show_users();

if (count($users)){
?>
<table border='1' cellspacing='0' cellpadding='5' width='500'>
<?php
foreach ($users as $key => $value){
echo "<tr valign='top'>\n";
echo "<td>".$key ."</td>\n";
echo "<td>".$value ." <small><a href='#'>follow</a></small></td>\n";
echo "</tr>\n";
}
?>
</table>
<?php
}else{
?>
<p><b>There are no users in the system!</b></p>
<?php
}
?>
</body>
</html>



為了訪問這個用戶列表,在 index.php 文件中表單的上方添加一個到 users.php 的鏈接:

<p><a href='users.php'>see list of users</a></p>



現在有了一個易於使用的用戶名列表,每個用戶名旁有一個 follow 鏈接。


圖 2. 用戶列表



在進入下一個階段之前,還需要編寫一個小函數,該函數將返回當前用戶正在追隨的用戶。這樣一來,用戶就可以用這個列表來確定是否追隨另一個用戶。

回到 functions.php 文件,添加一個名為 following() 的函數,如清單 12 所示。將當前用戶 ID 傳遞給該函數,就可以得到該用戶正在追隨的每個用戶的 ID。


清單 12. following() 函數

function following($userid){
$users = array();

$sql = "select distinct user_id from following
where follower_id = '$userid'";
$result = mysql_query($sql);

while($data = mysql_fetch_object($result)){
array_push($users, $data->user_id);

}

return $users;

}



現在可以在 users.php 上運行這個函數,檢查某個用戶 ID 是否在該數組中。如果在,則使用 unfollow 鏈接。如果不在,則使用默認的 follow 鏈接。清單 13 顯示修改後的代碼。


清單 13. 修改後的 users.php 文件,它將顯示 follow 和 unfollow 鏈接

<?php
$users = show_users();
$following = following($_SESSION['userid']);

if (count($users)){
?>
<table border='1' cellspacing='0' cellpadding='5' width='500'>
<?php
foreach ($users as $key => $value){
echo "<tr valign='top'>\n";
echo "<td>".$key ."</td>\n";
echo "<td>".$value;
if (in_array($key,$following)){
echo " <small>
<a href='action.php?id=$key&do=unfollow'>unfollow</a>
</small>";
}else{
echo " <small>
<a href='action.php?id=$key&do=follow'>follow</a>
</small>";
}
echo "</td>\n";
echo "</tr>\n";
}
?>



接下來的步驟很簡單:創建 follow 和 unfollow 鏈接使用的 action.php 文件。該文件接受兩個 GET 參數:一個用於用戶 ID,另一個用於 follow 或 unfollow。如清單 14 所示,這個文件和 add.php 文件一樣簡短。


清單 14. action.php 文件

<?php
session_start();
include_once("header.php");
include_once("functions.php");

$id = $_GET['id'];
$do = $_GET['do'];

switch ($do){
case "follow":
follow_user($_SESSION['userid'],$id);
$msg = "You have followed a user!";
break;

case "unfollow":
unfollow_user($_SESSION['userid'],$id);
$msg = "You have unfollowed a user!";
break;

}
$_SESSION['message'] = $msg;

header("Location:index.php");
?>



可以看到,這裡取決於之前選擇的鏈接,採取兩種不同的動作 — follow_user() 或 unfollow_user()。然後,設置一條消息,並將用戶重定向回 index.php 頁面。用戶回到 index.php 頁面后,不僅可以看到自己的消息,還可以看到他們追隨的用戶最近添加的消息。或者,如果之前選擇 unfollow 鏈接,那麼那個用戶的消息將從列表中消失。稍後需要在 index.php 中添加這點代碼。現在,將 follow_user() 和 unfollow_user() 函數添加到 functions.php 中。

對於這兩個函數要小心一點。不能只是因為用戶單擊了那個鏈接,就盲目地追隨或放棄追隨一個用戶。首先,需要檢查 following 表中是否存在這樣的關係。如果存在,那麼可以忽略請求(單擊 follow 鏈接時),或者接受請求(單擊 unfollow 鏈接時)。為簡單起見,編寫兩種情況下都可以使用的一個 check_count() 函數,如下面的清單所示。


清單 15. check_count() 函數

function check_count($first, $second){
$sql = "select count(*) from following
where user_id='$second' and follower_id='$first'";
$result = mysql_query($sql);

$row = mysql_fetch_row($result);
return $row[0];

}

function follow_user($me,$them){
$count = check_count($me,$them);

if ($count == 0){
$sql = "insert into following (user_id, follower_id)
values ($them,$me)";

$result = mysql_query($sql);
}
}


function unfollow_user($me,$them){
$count = check_count($me,$them);

if ($count != 0){
$sql = "delete from following
where user_id='$them' and follower_id='$me'
limit 1";

$result = mysql_query($sql);
}
}



接下來的步驟很容易:在主頁上顯示當前用戶正在追隨的其他用戶的列表。雖然已經有了一個 show_users() 函數,但那個函數是顯示所有 用戶。可以通過增加一個非必需的參數,輕鬆地改變這個函數的用途。這個參數是一個用戶 ID,可以用該參數將用戶列表限制為該用戶 ID 所追隨的那些用戶。

清單 16 中重新編寫的代碼所做的事情是檢查傳入的 $user_id 參數。如果該用戶 ID 大於 0,則使用一個查詢獲取此 ID 追隨的所有用戶的 ID。使用 implode() 函數將獲得的數組轉換為一個以逗號分隔的列表。然後將這個字元串 — 大致為 and id in (1,2,3...n) — 插入到已有的 SQL 查詢中,從而將用戶列表限制為該用戶正在追隨的那些用戶。


清單 16. 重新編寫的代碼,用於限制通過查詢獲得的用戶列表

function show_users($user_id=0){

if ($user_id > 0){
$follow = array();
$fsql = "select user_id from following
where follower_id='$user_id'";
$fresult = mysql_query($fsql);

while($f = mysql_fetch_object($fresult)){
array_push($follow, $f->user_id);
}

if (count($follow)){
$id_string = implode(',', $follow);
$extra = " and id in ($id_string)";

}else{
return array();
}

}

$users = array();
$sql = "select id, username from users
where status='active'
$extra order by username";


$result = mysql_query($sql);

while ($data = mysql_fetch_object($result)){
$users[$data->id] = $data->username;
}
return $users;
}



接下來,將清單 17 中的代碼添加到主頁中,用於顯示所有那些被追隨的用戶。


清單 17. 修改 index.php 以顯示被追隨的用戶

<h2>Users you're following</h2>

<?php
$users = show_users($_SESSION['userid']);

if (count($users)){
?>
<ul>
<?php
foreach ($users as $key => $value){
echo "<li>".$value."</li>\n";
}
?>
</ul>
<?php
}else{
?>
<p><b>You're not following anyone yet!</b></p>
<?php
}
?>


添加其他用戶?貼子

要將其他用戶的貼子添加到一個用戶的時間表(timeline)上,只需重用之前編寫的一些代碼。例如,現在已經知道如何獲得當前用戶正在追隨的用戶的列表。也知道如何獲得某個用戶發出的所有貼子。因此只需稍微修改後一個函數,使之能夠接受一個用戶列表,而不是單個用戶。

現在只需在 index.php 文件中將第一個函數上移一點,以便馬上使用它,然後使用通過該函數獲得的用戶 ID 列表,從他們的時間表中獲取一定數量的貼子 — 這裡不需要所有的貼子,只需 5 個左右。記住,要按日期倒序(最近的在上)排列那些用戶的貼子。

首先,為 show_posts() 函數增加一個 limit 參數,將它的值默認為 0。如果 limit 大於 0,則將一個限制值添加到用於檢索貼子的 SQL 語句中。另外要做的是將 $userid 參數放入到一個數組中,並將該數組解析到一個以逗號分隔的欄位中,最後將該欄位傳遞給 SQL 語句。這需要做一點額外工作,但是可以獲得豐厚的回報,因為如您所見,所有貼子都將以倒序顯示。


清單 18. 更新 show_posts(),以接受一個用戶數組

function show_posts($userid,$limit=0){
$posts = array();

$user_string = implode(',', $userid);
$extra = " and id in ($user_string)";

if ($limit > 0){
$extra = "limit $limit";
}else{
$extra = '';
}

$sql = "select user_id,body, stamp from posts
where user_id in ($user_string)
order by stamp desc $extra";
echo $sql;
$result = mysql_query($sql);

while($data = mysql_fetch_object($result)){
$posts[] = array( 'stamp' => $data->stamp,
'userid' => $data->user_id,
'body' => $data->body
);
}
return $posts;

}



現在回到 index.php 文件,將不止一個用戶 ID 傳遞給 show_posts(),如下面的清單所示。這其實很簡單,因為已經收集到了這些用戶。現在只需使用 array_keys() 取出鍵值,將會話變數加到數組中。這樣,傳遞的數組最少包含一個值(已登錄的當前用戶的 ID),最多則包含當前用戶 ID 和該用戶追隨的每個用戶的 ID。


清單 19. 將一個用戶數組傳遞給 show_posts() 函數

$users = show_users($_SESSION['userid']);
if (count($users)){
$myusers = array_keys($users);
}else{
$myusers = array();
}
$myusers[] = $_SESSION['userid'];

$posts = show_posts($myusers,5);




結束語

在本文中,您學習了如何構建一個簡單的基於 PHP 的微博客服務,該服務類似於 Twitter 和 Facebook 狀態更新工具。如果一切順利的話,您就可以得到現在這樣的成果,並將它添加到您的應用程序中,並根據需要加以定製。(責任編輯:A6)



[火星人 ] 使用 PHP 在站點上構建類似 Twitter 的系統已經有678次圍觀

http://coctec.com/docs/linux/show-post-68940.html