Кажется, что в наши дни все отправляют смс-сообщения на свой мобильный телефон или обновляют статус своей социальной сети каждые 5 минут. Неудивительно, что удобство доступа к Интернету из любого места в любое время сделало обмен сообщениями и фотографиями столь популярными. Я не могу себе представить, чтобы куда-нибудь ехать без моего сотового телефона на случай, если что-нибудь интересное может случиться, и я могу задокументировать это, как будто я был первым репортером на сцене.
Это первая статья из двух частей, в которой я покажу вам, как создать фотоблог как часть вашего личного веб-сайта, который вы можете обновить со своего телефона, просто отправив электронное письмо. Вы напишите скрипт для проверки входящих сообщений в учетной записи электронной почты на наличие новых сообщений с использованием POP3; скрипт извлечет строку темы сообщения, основной текст и вложения и соответственно обновит базу данных. Затем вы можете извлечь информацию из базы данных для отображения в своем блоге, на боковой панели или как вам угодно.
Вместо разработки мобильного приложения, такого как для Android или iPhone, код будет работать на веб-сервере и фактически будет независимым от платформы. Что касается PHP, я буду использовать расширения IMAP и Imagick, поэтому вы должны убедиться, что они установлены до начала работы.
Вопросы безопасности
По соображениям безопасности вам, очевидно, потребуется какой-то тип аутентификации. Для этого сначала нужно настроить личную учетную запись электронной почты для веб-сервера, о котором знают только вы. Это учетная запись, которая будет получать обновления. Затем вам понадобится вторая учетная запись электронной почты для вашего мобильного устройства для отправки обновлений. Я буду использовать личную электронную почту [email protected] и общедоступную электронную почту [email protected] в коде статей.
Уровень безопасности, который вы можете применить к учетной записи электронной почты сервера, зависит от того, какие административные привилегии у вас есть. В лучшем случае вы хотите, чтобы ваш почтовый сервер отклонял всю входящую почту в учетной записи, кроме как с публичного адреса вашего мобильного телефона. В худшем случае вы хотите, по крайней мере, убедиться, что его спам-фильтр установлен на максимально возможную настройку, и добавить свой мобильный адрес в белый список.
В качестве дополнительного уровня безопасности каждому письму, полученному [email protected], будет присвоен уникальный токен. Затем токен будет отправлен на ваш телефон вместе с краткой сводкой сообщения и попросит вас подтвердить. Чтобы обновить свой блог, вам нужно просто отправить электронное письмо, дождаться автоответчика и затем открыть предоставленную ссылку, чтобы подтвердить обновление. Автоответ будет отправлен скриптом, который выполняется каждые несколько минут как задание cron или, если у вас есть доступ к самому почтовому серверу, вы можете выбрать что-то вроде procmail или maildrop .
С этими мерами безопасности вы можете быть уверены, что ничего не будет опубликовано без вашего согласия.
База данных
Для этого проекта вам потребуется как минимум три таблицы: таблица blog_posts, в которой будут храниться идентификатор блога, заголовок блога, основной текст и метка времени; таблица изображений, в которой будут храниться идентификатор изображения, ссылка на идентификатор блога и путь к файлу, где изображение хранится на сервере; и ожидающая таблица, в которой будет храниться идентификатор сообщения, относящийся к номеру сообщения в папке входящих сообщений, уникальный 32-символьный токен MD5 и флаг, указывающий состояние подтверждения.
Это операторы CREATE TABLE для базы данных:
CREATE TABLE blog_posts (
post_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
body TEXT NOT NULL,
create_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (post_id)
);
CREATE TABLE images (
image_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
post_id INTEGER UNSIGNED NOT NULL,
image_path VARCHAR(200) NOT NULL,
PRIMARY KEY (image_id),
FOREIGN KEY (post_id) REFERENCES blog_posts(post_id)
);
CREATE TABLE pending (
message_id INTEGER UNSIGNED NOT NULL,
token CHAR(32) NOT NULL,
is_valid ENUM('Y','N') DEFAULT 'N',
PRIMARY KEY (message_id)
);
Получение электронной почты
Когда дело доходит до получения электронной почты, у вас есть возможность подключения с IMAP или POP3. Основное различие между ними заключается в способе хранения почты. POP3 ожидает, что вы будете хранить почту на своем компьютере, поэтому он предлагает только способ загрузки новой почты, после чего копия с сервера удаляется. IMAP, с другой стороны, больше похож на «веб-почту» в том смысле, что вся почта хранится и сохраняется на сервере, к которому вы обращаетесь удаленно, и поэтому предоставляет дополнительные функции, такие как управление папками. IMAP по понятным причинам является более сложным, что вы можете увидеть сами, сравнив RFC для двух протоколов.
Во всех отношениях POP3 справится с задачей, поскольку вам не нужны никакие специальные функции. PHP предоставляет функции для работы с почтовыми протоколами, включая POP3, с его расширением IMAP.
Документация по многим функциям расширения является пятнистой, и из-за этого их нелегко использовать. К счастью, набор функций- оболочек был написан и размещен в заметках Уайла Барата, предоставленных пользователем, которые предоставляют API, который намного проще в использовании. Следующий класс основан на коде Барата и должен быть скопирован и сохранен как POP3.php:
<?php
class POP3
{
private $conn;
// make connection
public function __construct($host, $user, $pass, $folder = "INBOX", $port = 110, $useSSL = false) {
$ssl = ($useSSL) ? "" : "/novalidate-cert";
$mailbox = sprintf("{%s:%d/pop3%s}%s", $host, $port, $ssl, $folder);
$this->conn = imap_open($mailbox, $user, $pass);
}
// close connection and trigger expunge
public function __destruct() {
imap_close($this->conn, CL_EXPUNGE);
}
// retrieve a list of messages
public function listMessages($msgNum = "") {
$msgList = array();
if ($msgNum) {
$range = $msgNum;
}
else {
$info = imap_check($this->conn);
$range = "1:" . $info->Nmsgs;
}
$response = imap_fetch_overview($this->conn, $range);
foreach ($response as $msg) {
$msgList[$msg->msgno] = (array)$msg;
}
return $msgList;
}
// delete a message
public function deleteMessage($msgNum) {
return imap_delete($this->conn, $msgNum);
}
// parse headers into usable code
public function parseHeaders($headers) {
$headers = preg_replace('/rns+/m', "", $headers);
preg_match_all('/([^: ]+): (.+?(?:rns(?:.+?))*)?rn/m',
$headers, $matches);
foreach ($matches[1] as $key => $value) {
$result[$value] = $matches[2][$key];
}
return $result;
}
// separate MIME types
public function mimeToArray($msgNum, $parseHeaders = false) {
$mail = imap_fetchstructure($this->conn, $msgNum);
$mail = $this->getParts($msgNum, $mail, 0);
if ($parseHeaders) {
$mail[0]["parsed"] = $this->parseHeaders($mail[0]["data"]);
}
return $mail;
}
// separate mail parts
public function getParts($msgNum, $part, $prefix) {
$attachments = array();
$attachments[$prefix] = $this->decodePart($msgNum, $part, $prefix);
// multi-part
if (isset($part->parts)) {
$prefix = ($prefix) ? $prefix . "." : "";
foreach ($part->parts as $number => $subpart) {
$attachments = array_merge($attachments, $this->getParts($msgNum, $subpart, $prefix . ($number + 1)));
}
}
return $attachments;
}
// fetch the body of an email with one part
public function fetchBody($msgNum = "") {
return imap_fetchbody($this->conn, $msgNum, 1);
}
// decode attachments
public function decodePart($msgNum, $part, $prefix) {
$attachment = array();
if ($part->ifdparameters) {
foreach ($part->dparameters as $obj) {
$attachment[strtolower($obj->attribute)] = $obj->value;
if (strtolower($obj->attribute) == "filename") {
$attachment["is_attachment"] = true;
$attachment["filename"] = $obj->value;
}
}
}
if ($part->ifparameters) {
foreach ($part->parameters as $obj) {
$attachment[strtolower($obj->attribute)] = $obj->value;
if (strtolower($obj->attribute) == "name") {
$attachment["is_attachment"] = true;
$attachment["name"] = $obj->value;
}
}
}
$attachment["data"] = imap_fetchbody($this->conn, $msgNum, $prefix);
// 3 is base64
if ($part->encoding == 3) {
$attachment["data"] = base64_decode($attachment["data"]);
}
// 4 is quoted-printable
elseif ($part->encoding == 4) {
$attachment["data"] = quoted_printable_decode($attachment["data"]);
}
return($attachment);
}
}
Конструктор класса устанавливает соединение с почтовым сервером. Возможность использования SSL-шифрования также доступна, если у вас есть сертификат. Деструктор закрывает соединение.
Метод listMessages()
Возвращенный список содержит не реальное содержимое письма, а адрес отправителя, адрес, строку темы и дату.
Метод deleteMessage()
Сообщение не будет фактически удалено, пока соединение не будет закрыто с соответствующим флагом, что делается в деструкторе класса.
Метод parseHeaders()
Метод mimeToArray()
Если найдено несколько типов MIME, это хороший признак наличия вложений.
Метод getParts()
Метод fetchBody()
Метод decodeParts()
С помощью этого класса вы можете теперь подключиться к серверу и получить полный список сообщений в папке входящих сообщений следующим образом.
<?php
require_once "POP3.php";
define("EMAIL_HOST", "pop.liberty2.say");
define("EMAIL_USER", "[email protected]");
define("EMAIL_PASSWD", "********");
$pop3 = new POP3(EMAIL_HOST, EMAIL_USER, EMAIL_PASSWD);
$msgList = $pop3->listMessages();
foreach ($msgList as $msg) {
echo "<pre>" . print_r($msg, true) . "</pre>";
}
Резюме
Это подводит нас к концу части 1. Пока у вас есть план игры для создания приложения и публикации только тех отправленных вами сообщений. У вас также есть схема базы данных и класс, который позволяет вам подключаться к серверу POP3 и получать сообщения. Обязательно вернитесь к части 2, чтобы увидеть, как эти части сочетаются друг с другом для реализации проекта.
Изображение через Анжелу Уэй / Shutterstock