—»     —»   Создаем скрипт в стиле Pinterest – Часть 5
  Раздел: Скрипты и коды   Нет комментариев  

Создаем скрипт в стиле Pinterest – Часть 5



Мы уже почти закончили наш скрипт в стиле Pinterest. В 5 части нашего руководства мы подготовили следующие вещи: функционал отметок и перепостов, а также поиск. Как вам известно, отметки «нравится» - это нечто вроде системы рейтинга. В нашем скрипте любой авторизованный пользователь может оценить любое фото (поставить отметку) раз в час (это система защиты от жульничества). Если вам нравится фотография, и вы хотите добавить ее в собственный профиль, вы можете нажать кнопку перепоста «repin». Это действие скопирует фотографию к вам на страницу (на самом деле, появится всего лишь одна новая запись в базе данных). Касательно поиска у нас все просто: мы подготовили строку поиска уже довольно давно, но до этого момента она не работала. Сегодня мы добавили этот функционал. Мы предлагаем вам обновленные исходники нашего скрипта в этой части. Если вы готовы, давайте приступим.

* Создаем скрипт в стиле Pinterest – Часть 1
* Создаем скрипт в стиле Pinterest – Часть 2
* Создаем скрипт в стиле Pinterest – Часть 3
* Создаем скрипт в стиле Pinterest – Часть 4

Создаем скрипт в стиле Pinterest – Часть 5

Сейчас как раз самое время опробовать наше обновленное демо, и скачать архив исходных файлов:

Посмотреть демо | Скачать архивом
Внимание! У вас нет прав для просмотра скрытого текста.


Этап 1 – SQL

Чтобы реализовать счетчик отметок и функционал перепостов, мы немного расширили нашу таблицу `pd_photos`.

CREATE TABLE IF NOT EXISTS `pd_photos` (
`id` int(10) unsigned NOT NULL auto_increment,
`title` varchar(255) default '',
`filename` varchar(255) default '',
`owner` int(11) NOT NULL,
`when` int(11) NOT NULL default '0',
`comments_count` int(11) NOT NULL default '0',
`repin_id` int(11) NOT NULL default '0',
`repin_count` int(11) NOT NULL default '0',
`like_count` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Если вы просто хотите обновить существующую таблицу, то просто запустите этот небольшой SQL-код:

ALTER TABLE `pd_photos`
ADD `repin_id` int(11) NOT NULL default '0',
ADD `repin_count` int(11) NOT NULL default '0',
ADD `like_count` int(11) NOT NULL default '0';

Наконец, мы подготовили новую SQL-таблицу, которая будет хранить строки вроде этих:

CREATE TABLE IF NOT EXISTS `pd_items_likes` (
`l_id` int(11) NOT NULL AUTO_INCREMENT ,
`l_item_id` int(12) NOT NULL default '0',
`l_pid` int(12) NOT NULL default '0',
`l_when` int(11) NOT NULL default '0',
PRIMARY KEY (`l_id`),
KEY `l_item_id` (`l_item_id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;

Этап 2 – PHP-код

Мы решили отобразить результаты поиска на странице index.php, и поэтому сюда нам нужно внести кое-какие корректировки. Вот так выглядит обновленная версия:

Index.php

require_once('classes/CMySQL.php');
require_once('classes/CMembers.php');
require_once('classes/CPhotos.php');

// get login data
list ($sLoginMenu, $sExtra) = $GLOBALS['CMembers']->getLoginData();

// get search keyword (if provided)
$sSearchParam = strip_tags($_GET['q']);

// get all photos
$sPhotos = $GLOBALS['CPhotos']->getAllPhotos(0, $sSearchParam);

if ($sSearchParam) {
$sExtra .= '<h2 class="pname">Search results for <strong>'.$sSearchParam.'</strong></h2>';
}

// draw common page
$aKeys = array(
'{menu_elements}' => $sLoginMenu,
'{extra_data}' => $sExtra,
'{images_set}' => $sPhotos
);
echo strtr(file_get_contents('templates/index.html'), $aKeys);

Теперь, как вы помните, мы используем файл service.php для выполнения различных методов. Рассмотрите нашу обновленную версию (в которую мы добавили возможность работать с кнопками ‘like’ и ‘repin’):

service.php

require_once('classes/CMySQL.php');
require_once('classes/CMembers.php');
require_once('classes/CPhotos.php');
require_once('classes/CComments.php');

if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
$GLOBALS['CMembers']->registerProfile();
}

$i = (int)$_GET['id'];

if ($_GET && $_GET['get'] == 'comments') {
header('Content-Type: text/html; charset=utf-8');
echo $GLOBALS['Comments']->getComments($i);
exit;
}
if ($_POST) {
header('Content-Type: text/html; charset=utf-8');
if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
switch($_POST['add']) {
case 'comment':
echo $GLOBALS['Comments']->acceptComment(); exit;
break;
case 'like':
echo $GLOBALS['CPhotos']->acceptLike(); exit;
break;
case 'repin':
echo $GLOBALS['CPhotos']->acceptRepin(); exit;
break;
}
}
echo '<h3>Please login first</h3>';
exit;
}

if (! $i) { // if something is wrong - relocate to error page
header('Location: error.php');
exit;
}

$aPhotoInfo = $GLOBALS['CPhotos']->getPhotoInfo($i);
$aOwnerInfo = $GLOBALS['CMembers']->getProfileInfo($aPhotoInfo['owner']);

$sOwnerName = ($aOwnerInfo['first_name']) ? $aOwnerInfo['first_name'] : $aOwnerInfo['email'];
$sPhotoTitle = $aPhotoInfo['title'];
$sPhotoDate = ($aPhotoInfo['repin_id'] == 0) ? 'Uploaded on ' : 'Repinned on ';
$sPhotoDate .= $GLOBALS['CPhotos']->formatTime($aPhotoInfo['when']);

$sFolder = 'photos/';
$sFullImgPath = $sFolder . 'f_' . $aPhotoInfo['filename'];
$aSize = getimagesize($sFullImgPath); // get image info
$iWidth = $aSize[0];
$iHeight = $aSize[1];

// repin possibility to logged members
$iLoggId = (int)$_SESSION['member_id'];
$sActions = ($iLoggId && $aPhotoInfo['owner'] != $iLoggId) ? '<a href="#" class="button repinbutton" onclick="return repinPhoto(this);">Repin</a>' : '';

?>
<div class="pin bigpin" bpin_id="<?= $i ?>">
<div class="owner">
<a href="#" class="button follow_button">Follow</a>
<a class="owner_img" href="profile.php?id=<?= $aOwnerInfo['id'] ?>">
<img alt="<?= $sOwnerName ?>" src="images/avatar.jpg" />
</a>
<p class="owner_name"><a href="profile.php?id=<?= $aOwnerInfo['id'] ?>"><?= $sOwnerName ?></a></p>
<p class="owner_when"><?= $sPhotoDate ?></p>
</div>
<div class="holder">
<div class="actions">
<?= $sActions ?>
</div>
<a class="image" href="#" title="<?= $sPhotoTitle ?>">
<img alt="<?= $sPhotoTitle ?>" src="<?= $sFullImgPath ?>" style="width:<?= $iWidth ?>px;height:<?= $iHeight ?>px;" />
</a>
</div>

<p class="desc"><?= $sPhotoTitle ?></p>

<div class="comments"></div>

<script>
function submitCommentAjx() {
$.ajax({
type: 'POST',
url: 'service.php',
data: 'add=comment&id=' + <?= $i ?> + '&comment=' + $('#pcomment').val(),
cache: false,
success: function(html){
if (html) {
$('.comments').html(html);
$(this).colorbox.resize();
}
}
});
}
function repinPhoto(obj) {
var iPinId = $(obj).parent().parent().parent().attr('bpin_id');
$.ajax({
url: 'service.php',
type: 'POST',
data: 'add=repin&id=' + iPinId,
cache: false,
success: function(res){
window.location.href = 'profile.php?id=' + res;
}
});
return false;
}
</script>
<form class="comment" method="post" action="#">
<textarea placeholder="Add a comment..." maxlength="255" id="pcomment"></textarea>
<button type="button" class="button" onclick="return submitCommentAjx()">Comment</button>
</form>
</div>

Следующий обновленный файл – это основной класс Photos:

classes/CPhotos.php

/*
* Photos class
*/
class CPhotos {

// constructor
function CPhotos() {
}

// get all photos
function getAllPhotos($iPid = 0, $sKeyPar = '') {

// prepare WHERE filter
$aWhere = array();
if ($iPid) {
$aWhere[] = "`owner` = '{$iPid}'";
}
if ($sKeyPar != '') {
$sKeyword = $GLOBALS['MySQL']->escape($sKeyPar);
$aWhere[] = "`title` LIKE '%{$sKeyword}%'";
}
$sFilter = (count($aWhere)) ? 'WHERE ' . implode(' AND ', $aWhere) : '';

$sSQL = "
SELECT *
FROM `pd_photos`
{$sFilter}
ORDER BY `when` DESC
";
$aPhotos = $GLOBALS['MySQL']->getAll($sSQL);

$sPhotos = '';
$sFolder = 'photos/';
foreach ($aPhotos as $i => $aPhoto) {

$iPhotoId = (int)$aPhoto['id'];
$sFile = $aPhoto['filename'];
$sTitle = $aPhoto['title'];
$iCmts = (int)$aPhoto['comments_count'];

$iLoggId = (int)$_SESSION['member_id'];
$iOwner = (int)$aPhoto['owner'];
$iRepins = (int)$aPhoto['repin_count'];
$iLikes = (int)$aPhoto['like_count'];
$sActions = ($iLoggId && $iOwner != $iLoggId) ? '<a href="#" class="button repinbutton">Repin</a><a href="#" class="button likebutton">Like</a>' : '';

$aPathInfo = pathinfo($sFolder . $sFile);
$sExt = strtolower($aPathInfo['extension']);

$sImages .= <<<EOL
<!-- pin element {$iPhotoId} -->
<div class="pin" pin_id="{$iPhotoId}">
<div class="holder">
<div class="actions">
{$sActions}
<a href="#" class="button comment_tr">Comment</a>
</div>
<a class="image ajax" href="service.php?id={$iPhotoId}" title="{$sTitle}">
<img alt="{$sTitle}" src="{$sFolder}{$sFile}">
</a>
</div>
<p class="desc">{$sTitle}</p>
<p class="info">
<span class="LikesCount"><strong>{$iLikes}</strong> likes</span>
<span>{$iRepins} repins</span>
<span>{$iCmts} comments</span>
</p>
<form class="comment" method="post" action="" style="display: none" onsubmit="return submitComment(this, {$iPhotoId})">
<textarea placeholder="Add a comment..." maxlength="255" name="comment"></textarea>
<input type="submit" class="button" value="Comment" />
</form>
</div>
EOL;
}
return $sImages;
}

// get certain photo info
function getPhotoInfo($i) {
$sSQL = "SELECT * FROM `pd_photos` WHERE `id` = '{$i}'";
$aInfos = $GLOBALS['MySQL']->getAll($sSQL);
return $aInfos[0];
}

// format time by timestamp
function formatTime($iSec) {
$sFormat = 'j F Y';
return gmdate($sFormat, $iSec);
}

// insert a new blank photo into DB
function insertBlankPhoto($sTitle, $iOwner) {
$sTitle = $GLOBALS['MySQL']->escape($sTitle);
$iOwner = (int)$iOwner;

$sSQL = "INSERT INTO `pd_photos` SET `title` = '{$sTitle}', `owner` = '{$iOwner}', `when` = UNIX_TIMESTAMP()";
$GLOBALS['MySQL']->res($sSQL);
return $GLOBALS['MySQL']->lastId();
}

// update filename
function updateFilename($i, $sFilename) {
$sFilename = $GLOBALS['MySQL']->escape($sFilename);

$sSQL = "UPDATE `pd_photos` SET `filename` = '{$sFilename}' WHERE `id`='{$i}'";
return $GLOBALS['MySQL']->res($sSQL);
}

function acceptLike() {
$iItemId = (int)$_POST['id']; // prepare necessary information
$iLoggId = (int)$_SESSION['member_id'];

if ($iItemId && $iLoggId) {
// check - if there is any recent record from the same person for last 1 hour
$iOldId = $GLOBALS['MySQL']->getOne("SELECT `l_item_id` FROM `pd_items_likes` WHERE `l_item_id` = '{$iItemId}' AND `l_pid` = '{$iLoggId}' AND `l_when` >= UNIX_TIMESTAMP() - 3600 LIMIT 1");
if (! $iOldId) {
// if everything is fine - we can add a new like
$GLOBALS['MySQL']->res("INSERT INTO `pd_items_likes` SET `l_item_id` = '{$iItemId}', `l_pid` = '{$iLoggId}', `l_when` = UNIX_TIMESTAMP()");
// and update total amount of likes
$GLOBALS['MySQL']->res("UPDATE `pd_photos` SET `like_count` = `like_count` + 1 WHERE `id` = '{$iItemId}'");
}
// and return total amount of likes
return (int)$GLOBALS['MySQL']->getOne("SELECT `like_count` FROM `pd_photos` WHERE `id` = '{$iItemId}'");
}
}
function acceptRepin() {
$iItemId = (int)$_POST['id']; // prepare necessary information
$iLoggId = (int)$_SESSION['member_id'];

if ($iItemId && $iLoggId) {
$aPhotoInfo = $this->getPhotoInfo($iItemId);

// check - for already repinned element
$iOldId = $GLOBALS['MySQL']->getOne("SELECT `id` FROM `pd_photos` WHERE `owner` = '{$iLoggId}' AND `repin_id` = '{$iItemId}'");
if (! $iOldId) {
// if everything is fine - add a copy of photo as own photo (repin)
$sSQL = "INSERT INTO `pd_photos` SET
`title` = '{$aPhotoInfo['title']}',
`filename` = '{$aPhotoInfo['filename']}',
`owner` = '{$iLoggId}',
`when` = UNIX_TIMESTAMP(),
`repin_id` = '{$iItemId}'
";
$GLOBALS['MySQL']->res($sSQL);

// update repin count for original photo
$GLOBALS['MySQL']->res("UPDATE `pd_photos` SET `repin_count` = `repin_count` + 1 WHERE `id` = '{$iItemId}'");
}
// and return current member id
return $iLoggId;
}
}

}

$GLOBALS['CPhotos'] = new CPhotos();

Вы можете видеть, что мы изменили функцию ‘getAllPhotos’. Теперь она может работать с поисковыми параметрами, а также отображать счетчики перепостов и отметок. С сегодняшнего дня, кнопки перепоста и отметки доступны только для авторизованных пользователей. Вы также можете видеть две новые функции ‘acceptLike’ и ‘acceptRepin’. Первая принимает отметки, а вторая работает с перепостами. Как видно, она просто создает новую запись в базе данных (копию перепубликованного объекта), но только с ссылкой на исходного фото (поле repin_id).

Этап 3 – javascript

Мы также обновили наш основной файл javascript. Здесь есть только два новых обработчика событий:

js/script.js

// onclick event handler (for like button)
$('.pin .actions .likebutton').click(function () {
$(this).attr('disabled', 'disabled');

var iPinId = $(this).parent().parent().parent().attr('pin_id');
$.ajax({
url: 'service.php',
type: 'POST',
data: 'add=like&id=' + iPinId,
cache: false,
success: function(res){
$('.pin[pin_id='+iPinId+'] .info .LikesCount strong').text(res);
}
});
return false;
});

// onclick event handler (for repin button)
$('.pin .actions .repinbutton').click(function () {
var iPinId = $(this).parent().parent().parent().attr('pin_id');
$.ajax({
url: 'service.php',
type: 'POST',
data: 'add=repin&id=' + iPinId,
cache: false,
success: function(res){
window.location.href = 'profile.php?id=' + res;
}
});
return false;
});

Главная идея заключается в использовании jQuery Ajax для того, чтобы отсылать необходимую информацию об отметках и перепостах в наш серверный файл ‘service.php’. Как только мы кликаем по кнопке like, мы посылаем id фотографии, а затем сервер возвращает нам общее количество отметок к данному фото, и мы можем обновлять счетчик отметок. В случае с кнопкой перепостов все примерно так же. Мы отправляем id фото на сервер и, как только он перепубликует выбранное фото, он перенаправляет нас на страницу профайла (где мы можем видеть результат).

Завершение

Только что мы закончили 5 часть из нашей серии статей, посвященных разработке скрипта наподобие Pinterest. Надеемся, что вам понравился этот урок, и вы обязательно поделитесь им с друзьями! Удачи вам, и возвращайтесь!
Обнаружили ошибку или мёртвую ссылку?
Выделите проблемный фрагмент мышкой и нажмите CTRL+ENTER.
В появившемся окне опишите проблему и отправьте уведомление Администрации ресурса.
Нужна органическая вечная ссылка из данной статьи? Постовой?
Подробности здесь
Вам понравился материал? Поблагодарить легко!
Будем весьма признательны, если поделитесь этой статьей в социальных сетях:

Ключевые тэги: Pinterest, скрипты
Опубликовал Design FactoRy   Прочитано (раз): 5809   |   Нет комментариев
Автор перевода — CoolWebmasters.Com ©   |   Источник материала / оригинал статьи   Распечатать
Другие статьи и новости по теме:
Добавление комментария
Уважаемые пользователи!
При добавлении комментариев на сайт Вам следует учитывать следующее - все комментарии проверяются Администрацией на предмет отсутствия спама. При обнаружении признаков спама, в оставленном Вами комментарии, сам комментарий будет незамедлительно удалён, а Ваш IP-адрес будет забанен без предупреждения! Учётные записи пользователей, рассылающих спам, блокируются/удаляются без права последующего восстановления.

С уважением, Администрация сайта.
* = поля обязательны к заполнению
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Вопрос : Национальная денежная единица США
Подтверждение кода безопасности :

Включите эту картинку для отображения кода безопасности
обновить, если не виден код


Популярные публикации


















Свежие шаблоны сайтов каждый день
С миру по нитке
«    Сентябрь 2017    »
ПнВтСрЧтПтСбВс
 123
45678910
11121314151617
18192021222324
252627282930