How to create Pinterest-like script – step 3
I hope you’re looking forward to a new lesson. For today I prepared few important changes. For the first – this is a new login and registration system for our script, the second – since today we are going to use database to keep information about members, photos, and for future comments. Now, you need to log in to be able to upload photos. Today I’ll publish all updated files of our script, in case if you want to investigate everything at your local computer – you always can download full package with sources.
Now you can check our demo and download the sources here:
Live Demo
[sociallocker]
download in package
[/sociallocker]
Step 1. SQL
To better understand how it works – let’s look at all the new database tables:
CREATE TABLE `pd_profiles` ( `id` int(10) unsigned NOT NULL auto_increment, `first_name` varchar(255) NOT NULL default '', `last_name` varchar(255) NOT NULL default '', `email` varchar(255) NOT NULL default '', `password` varchar(40) NOT NULL default '', `salt` varchar(10) NOT NULL default '', `status` enum('active','passive') NOT NULL default 'active', `role` tinyint(4) unsigned NOT NULL default '1', `date_reg` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `pd_profiles` (`first_name`, `last_name`, `email`, `password`, `salt`, `status`, `role`, `date_reg`) VALUES ('test user first name', 'test user last name', 'user@user.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 1, NOW()), ('moderator first name', 'moderator last name', 'moderator@moderator.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 2, NOW()), ('admin first name', 'admin last name', 'admin@admin.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 3, NOW()), ('test user 2 first name', 'test user 2 last name', 'user2@user.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 1, NOW()); 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', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `pd_photos` (`title`, `filename`, `owner`, `when`) VALUES ('Item #1', 'pic1.jpg', 1, UNIX_TIMESTAMP()), ('Item #2', 'pic2.jpg', 2, UNIX_TIMESTAMP()+1), ('Item #3', 'pic3.jpg', 3, UNIX_TIMESTAMP()+2), ('Item #4', 'pic4.jpg', 4, UNIX_TIMESTAMP()+3); CREATE TABLE IF NOT EXISTS `pd_items_cmts` ( `c_id` int(11) NOT NULL AUTO_INCREMENT , `c_item_id` int(12) NOT NULL default '0', `c_ip` varchar(20) default NULL, `c_name` varchar(64) default '', `c_text` text NOT NULL , `c_when` int(11) NOT NULL default '0', PRIMARY KEY (`c_id`), KEY `c_item_id` (`c_item_id`) ) ENGINE=MYISAM DEFAULT CHARSET=utf8;
There are three tables, the first one (pd_profiles) keeps information about members, the second one (pd_photos) keep info about all photos, and the third one is for comments. Please pay attention, that all members have the same password: ‘password’. You have to use email and password to login into system.
Step 2. HTML
I made small corrections in our ‘index.html’ template file. As you know, we don’t have to display upload form for usual visitors, it is only for logged in members. But, we have to display login and join forms for visitors. Please look at updated html markup of our index page:
templates/index.html
<!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" /> <meta name="author" content="Script Tutorials" /> <title>How to create Pinterest-like script - step 3 | Script Tutorials</title> <!-- add styles --> <link href="css/main.css" rel="stylesheet" type="text/css" /> <link href="css/colorbox.css" rel="stylesheet" type="text/css" /> <!-- add scripts --> <script src="js/jquery.min.js"></script> <script src="js/jquery.colorbox-min.js"></script> <script src="js/jquery.masonry.min.js"></script> <script src="js/script.js"></script> </head> <body> <!-- header panel --> <div class="header_panel"> <!-- logo --> <a href="#" class="logo"></a> <!-- search form --> <form action="" method="get" class="search"> <input autocomplete="off" name="q" size="27" placeholder="Search" type="text" /> <input name="search" type="submit" /> </form> <!-- navigation menu --> <ul class="nav"> <li> <a href="#">About<span></span></a> <ul> <li><a href="#">Help</a></li> <li><a href="#">Pin It Button</a></li> <li><a href="#" target="_blank">For Businesses</a></li> <li class="div"><a href="#">Careers</a></li> <li><a href="#">Team</a></li> <li><a href="#">Blog</a></li> <li class="div"><a href="#">Terms of Service</a></li> <li><a href="#">Privacy Policy</a></li> <li><a href="#">Copyright</a></li> <li><a href="#">Trademark</a></li> </ul> </li> {menu_elements} <li> <a href="https://www.script-tutorials.com/pinterest-like-script-step-3/">Back to tutorial</a> </li> </ul> </div> {extra_data} <!-- main container --> <div class="main_container"> {images_set} </div> </body> </html>
As you see – I added two new template keys: {menu_elements} – this keys will contain extra join and login forms for visitors, and Upload, Profile and Logout menu elements for logged-in members. Our new key {extra_data} contains join and login forms for visitors, and upload form for members. All these forms – pure CSS-driven forms.
Step 3. PHP
As you might imagine – all our php files were modified. Let’s start with main index file:
index.php
// set warning level if (version_compare(phpversion(), '5.3.0', '>=') == 1) error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); else error_reporting(E_ALL & ~E_NOTICE); 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 all photos $sPhotos = $GLOBALS['CPhotos']->getAllPhotos(); // draw common page $aKeys = array( '{menu_elements}' => $sLoginMenu, '{extra_data}' => $sExtra, '{images_set}' => $sPhotos ); echo strtr(file_get_contents('templates/index.html'), $aKeys);
As you see – it is much smaller now. But in the same time you can see that I added three new classes: CMySQL (to work with database), CMembers (to work with members) and CPhotos (to work with photos). Well, this file displays Login and Join forms for visitors and Upload form for active members. Also, we display all photos at this page. The second updated file is:
service.php
// set warning level if (version_compare(phpversion(), '5.3.0', '>=') == 1) error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); else error_reporting(E_ALL & ~E_NOTICE); require_once('classes/CMySQL.php'); require_once('classes/CMembers.php'); require_once('classes/CPhotos.php'); if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') { $GLOBALS['CMembers']->registerProfile(); } $i = (int)$_GET['id']; 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 = $GLOBALS['CPhotos']->formatTime($aPhotoInfo['when']); $sFolder = 'photos/'; $sFullImgPath = $sFolder . 'f_' . $aPhotoInfo['filename']; ?> <div class="pin bigpin"> <div class="owner"> <a href="#" class="button follow_button">Follow</a> <a target="_blank" class="owner_img" href="#"> <img alt="<?= $sOwnerName ?>" src="images/avatar.jpg" /> </a> <p class="owner_name"><a target="_blank" href="#"><?= $sOwnerName ?></a></p> <p class="owner_when">Uploaded on <?= $sPhotoDate ?></p> </div> <div class="holder"> <div class="actions"> <a href="#" class="button">Repin</a> <a href="#" class="button">Like</a> </div> <a class="image" href="#" title="<?= $sPhotoTitle ?>"> <img alt="<?= $sPhotoTitle ?>" src="<?= $sFullImgPath ?>"> </a> </div> <p class="desc"><?= $sPhotoTitle ?></p> <div class="comments"></div> <form class="comment" method="post" action="#"> <input type="hidden" name="id" value="0" /> <textarea placeholder="Add a comment..." maxlength="1000"></textarea> <button type="button" class="button">Comment</button> </form> </div>
I just added an user registration. In addition, we do not need to pass the full name of the file to see larger version. Instead, we pass the image ID. The next updated file is uploader:
upload.php
// set warning level if (version_compare(phpversion(), '5.3.0', '>=') == 1) error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); else error_reporting(E_ALL & ~E_NOTICE); require_once('classes/CMySQL.php'); require_once('classes/CMembers.php'); require_once('classes/CPhotos.php'); function uploadImageFile() { // Note: GD library is required for this upload function $iDefWidth = 192; // default photos width (in case of resize) $iFDefWidth = 556; // full default photos width (in case of resize) if ($_SERVER['REQUEST_METHOD'] == 'POST') { $iWidth = $iHeight = $iFDefWidth; // desired image dimensions $iJpgQuality = 75; if ($_FILES) { // if there are no errors and filesize less than 400kb if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 400 * 1024) { if (is_uploaded_file($_FILES['image_file']['tmp_name'])) { // new unique filename $sTempFileName = 'photos/' . md5(time().rand()); // move uploaded file into cache folder move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName); // change file permission to 644 @chmod($sTempFileName, 0644); // if temp file exists if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) { $aSize = getimagesize($sTempFileName); // obtain image info if (!$aSize) { @unlink($sTempFileName); return; } // check for image type and create a new image from file switch($aSize[2]) { case IMAGETYPE_JPEG: $sExt = '.jpg'; $vImg = @imagecreatefromjpeg($sTempFileName); break; case IMAGETYPE_PNG: $sExt = '.png'; $vImg = @imagecreatefrompng($sTempFileName); break; default: @unlink($sTempFileName); return; } // get source image width and height $iSrcWidth = imagesx($vImg); $iSrcHeight = imagesy($vImg); // recalculate height (depends on width) $iHeight = $iSrcHeight * $iWidth / $iSrcWidth; // create a new true color image $vDstImg = @imagecreatetruecolor($iWidth, $iHeight); // copy and resize imagecopyresampled($vDstImg, $vImg, 0, 0, 0, 0, $iWidth, $iHeight, $iSrcWidth, $iSrcHeight); // add a blank image object into DB $iLastId = $GLOBALS['CPhotos']->insertBlankPhoto($_FILES['image_file']['name'], $_SESSION['member_id']); // define a result image filename $sResultFileName = 'photos/f_pic' . $iLastId . $sExt; // update filename for our object $GLOBALS['CPhotos']->updateFilename($iLastId, 'pic' . $iLastId . $sExt); // output image to file and set permission 644 imagejpeg($vDstImg, $sResultFileName, $iJpgQuality); @chmod($sResultFileName, 0644); // and, prepare a thumbnail as well $iWidth = $iDefWidth; $iHeight = $iSrcHeight * $iWidth / $iSrcWidth; $vDstThImg = @imagecreatetruecolor($iWidth, $iHeight); imagecopyresampled($vDstThImg, $vImg, 0, 0, 0, 0, $iWidth, $iHeight, $iSrcWidth, $iSrcHeight); $sResultThumnName = 'photos/pic' . $iLastId . $sExt; imagejpeg($vDstThImg, $sResultThumnName, $iJpgQuality); @chmod($sResultThumnName, 0644); // unlink temp file @unlink($sTempFileName); return $sResultFileName; } } } } } } // upload available only for logged in members if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) { $sImage = uploadImageFile(); echo '1'; }
Now, only logged members can upload photos (as I told in the beginning). Well, I think that now it is important to review all our new classes as well:
classes/CMembers.php
/* * Members class */ class CMembers { // constructor function CMembers() { session_start(); } // get login box function function getLoginData() { if (isset($_GET['logout'])) { // logout process if (isset($_SESSION['member_email']) && isset($_SESSION['member_pass'])) $this->performLogout(); } if ($_POST && $_POST['email'] && $_POST['password']) { // login process if ($this->checkLogin($_POST['email'], $_POST['password'], false)) { // successful login $this->performLogin($_POST['email'], $_POST['password']); header('Location: index.php'); exit; } } else { // in case if we are already logged in if (isset($_SESSION['member_email']) && $_SESSION['member_email'] && $_SESSION['member_pass']) { $aReplaces = array( '{name}' => $_SESSION['member_email'], '{status}' => $_SESSION['member_status'], '{role}' => $_SESSION['member_role'], ); // display Profiles menu and Logout $sLoginMenu = <<<EOF <li><a href="#add_form" id="add_pop">Add +</a></li> <li> <a href="#">Profile<span></span></a> <ul> <li><a href="#">Invite Friends</a></li> <li><a href="#">Find Friends</a></li> <li class="div"><a href="#">Boards</a></li> <li><a href="#">Pins</a></li> <li><a href="#">Likes</a></li> <li class="div"><a href="#">Settings</a></li> <li><a href="#">Logout</a></li> </ul> </li> <li><a href="index.php?logout">Logout</a></li> EOF; $sExtra = <<<EOF <!-- upload form --> <a href="#x" class="overlay" id="add_form"></a> <div class="popup"> <div class="header"> <a class="close" href="#close">x</a> <h2>Upload a Pin</h2> </div> <form id="upload_form"> <input type="file" name="image_file" id="image_file" onchange="" /> </form> <div id="upload_result"></div> </div> EOF; return array($sLoginMenu, $sExtra); } } // display Join and Login menu buttons $sLoginMenu = <<<EOF <li><a href="#join_form" id="join_pop">Join</a></li> <li><a href="#login_form" id="login_pop">Login</a></li> EOF; $sExtra = <<<EOF <!-- join form --> <a href="#x" class="overlay2" id="join_form"></a> <div class="popup"> <div class="header"> <a class="close" href="#close">x</a> <h2>Create your account</h2> </div> <form method="POST" action="service.php"> <ul class="ctrl_grp"> <li> <input type="text" name="email" /> <label>Email Address</label> <span class="fff"></span> </li> <li> <input type="password" name="password" /> <label>Password</label> <span class="fff"></span> </li> <li> <input type="text" name="first_name" /> <label>First Name</label> <span class="fff"></span> </li> <li> <input type="text" name="last_name" /> <label>Last Name</label> <span class="fff"></span> </li> </ul> <div> <input type="hidden" name="Join" value="Join" /> <button class="submit_button" type="submit">Create Account</button> </div> </form> </div> <!-- login form --> <a href="#x" class="overlay3" id="login_form"></a> <div class="popup"> <div class="header"> <a class="close" href="#close">x</a> <h2>Login</h2> </div> <form method="POST" action="index.php"> <ul class="ctrl_grp"> <li> <input type="text" name="email" id="id_email"> <label>Email</label> <span class="fff"></span> </li> <li> <input type="password" name="password" id="id_password"> <label>Password</label> <span class="fff"></span> </li> </ul> <div> <button class="submit_button" type="submit">Login</button> </div> </form> </div> EOF; return array($sLoginMenu, $sExtra); } // perform login function performLogin($sEmail, $sPass) { $this->performLogout(); // make variables safe $sEmail = $GLOBALS['MySQL']->escape($sEmail); $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `pd_profiles` WHERE `email`='{$sEmail}'"); // $sPassEn = $aProfile['password']; $iPid = $aProfile['id']; $sSalt = $aProfile['salt']; $sStatus = $aProfile['status']; $sRole = $aProfile['role']; $sPass = sha1(md5($sPass) . $sSalt); $_SESSION['member_id'] = $iPid; $_SESSION['member_email'] = $sEmail; $_SESSION['member_pass'] = $sPass; $_SESSION['member_status'] = $sStatus; $_SESSION['member_role'] = $sRole; } // perform logout function performLogout() { unset($_SESSION['member_id']); unset($_SESSION['member_email']); unset($_SESSION['member_pass']); unset($_SESSION['member_status']); unset($_SESSION['member_role']); } // check login function checkLogin($sEmail, $sPass, $isHash = true) { // escape variables to make them self $sEmail = $GLOBALS['MySQL']->escape($sEmail); $sPass = $GLOBALS['MySQL']->escape($sPass); $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `pd_profiles` WHERE `email`='{$sEmail}'"); $sPassEn = $aProfile['password']; if ($sEmail && $sPass && $sPassEn) { if (! $isHash) { $sSalt = $aProfile['salt']; $sPass = sha1(md5($sPass) . $sSalt); } return ($sPass == $sPassEn); } return false; } // profile registration function registerProfile() { $sFirstname = $GLOBALS['MySQL']->escape($_POST['first_name']); $sLastname = $GLOBALS['MySQL']->escape($_POST['last_name']); $sEmail = $GLOBALS['MySQL']->escape($_POST['email']); $sPassword = $GLOBALS['MySQL']->escape($_POST['password']); if ($sEmail && $sPassword) { // check if email is already exists $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `pd_profiles` WHERE `email`='{$sEmail}'"); if ($aProfile['id'] > 0) { // relocate to 'error' page header('Location: error.php'); } else { // generate Salt and Cached password $sSalt = $this->getRandSaltCode(); $sPass = sha1(md5($sPassword) . $sSalt); // add new member into database $sSQL = " INSERT INTO `pd_profiles` SET `first_name` = '{$sFirstname}', `last_name` = '{$sLastname}', `email` = '{$sEmail}', `password` = '{$sPass}', `salt` = '{$sSalt}', `status` = 'active', `role` = '1', `date_reg` = NOW(); "; $GLOBALS['MySQL']->res($sSQL); // autologin $this->performLogin($sEmail, $sPassword); // relocate back to index page header('Location: index.php'); } } else { // otherwise - relocate to error page header('Location: error.php'); } } // get random salt code function getRandSaltCode($iLen = 8) { $sRes = ''; $sChars = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'; for ($i = 0; $i < $iLen; $i++) { $z = rand(0, strlen($sChars) -1); $sRes .= $sChars[$z]; } return $sRes; } // get certain member info function getProfileInfo($i) { $sSQL = " SELECT * FROM `pd_profiles` WHERE `id` = '{$i}' "; $aInfos = $GLOBALS['MySQL']->getAll($sSQL); return $aInfos[0]; } } $GLOBALS['CMembers'] = new CMembers();
The main members class contains next functions: getLoginData (this functions does several functions: login and logout processing, also it returns Join & Login menu buttons (with forms) and Upload & Logout buttons (with forms) for members), performLogin (to login), performLogout (to logout), checkLogin (to check login information), registerProfile (to register a new member), getRandSaltCode (to get random salt code), getProfileInfo (to get info about certain member). I think that it is enough functions for members for now. As you noticed, I use a new php file: error.php to generate errors, this is the very easy file:
error.php
require_once('classes/CMySQL.php'); require_once('classes/CMembers.php'); // login system init and generation code list ($sLoginMenu, $sExtra) = $GLOBALS['CMembers']->getLoginData(); // draw common page $aKeys = array( '{menu_elements}' => $sLoginMenu, '{extra_data}' => $sExtra, '{images_set}' => '<center><h1>Error Occurred, please try again</h1></center>' ); echo strtr(file_get_contents('templates/index.html'), $aKeys);
…Finally, our last new class for today is:
classes/CPhotos.php
/* * Photos class */ class CPhotos { // constructor function CPhotos() { } // get all photos function getAllPhotos() { $sSQL = " SELECT * FROM `pd_photos` 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']; $aPathInfo = pathinfo($sFolder . $sFile); $sExt = strtolower($aPathInfo['extension']); $sImages .= <<<EOL <!-- pin element {$iPhotoId} --> <div class="pin"> <div class="holder"> <div class="actions" pin_id="{$iPhotoId}"> <a href="#" class="button">Repin</a> <a href="#" class="button">Like</a> <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>XX likes</span> <span>XX repins</span> </p> <form class="comment" method="post" action="" style="display: none"> <input type="hidden" name="id" value="0" /> <textarea placeholder="Add a comment..." maxlength="1000"></textarea> <button type="button" class="button">Comment</button> </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); } } $GLOBALS['CPhotos'] = new CPhotos();
There are several more functions like: getAllPhotos (to get all set of photos for our index page), getPhotoInfo (to get info about certain image), formatTime (to format time for bigger popup version), insertBlankPhoto and updateFilename (to add a new image into database and update filename for that image)
Step 4. CSS
In order to handle with two new forms (Join and Login) I had to update a bit popup styles:
css/main.css
/* upload form styles */ .overlay, .overlay2, .overlay3 { background-color: #FFFFFF; bottom: 0; display: none; left: 0; opacity: 0.8; position: fixed; right: 0; top: 0; z-index: 9; } .overlay:target, .overlay2:target, .overlay3:target { display: block; } .popup { background: none repeat scroll 0 0 #FCF9F9; border: 1px solid #F7F5F5; box-shadow: 0 2px 5px rgba(34, 25, 25, 0.5); display: inline-block; left: 50%; padding: 30px 30px 20px; position: fixed; top: 40%; visibility: hidden; width: 550px; z-index: 10; -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); -o-transform: translate(-50%, -50%); transform: translate(-50%, -50%); -webkit-transition: all 0.3s ease-in-out 0s; -moz-transition: all 0.3s ease-in-out 0s; -ms-transition: all 0.3s ease-in-out 0s; -o-transition: all 0.3s ease-in-out 0s; transition: all 0.3s ease-in-out 0s; } .overlay:target+.popup, .overlay2:target+.popup, .overlay3:target+.popup { top: 50%; opacity: 1 ; visibility: visible; }
And, I added new styles for our new both forms:
/* login & join form styles */ .ctrl_grp li { display: block; font-size: 21px; list-style: none outside none; margin-bottom: 18px; position: relative; } .ctrl_grp input[type="text"], .ctrl_grp input[type="password"] { background-color: transparent; border: 1px solid #AD9C9C; border-radius: 6px 6px 6px 6px; box-shadow: 0 1px rgba(34, 25, 25, 0.15) inset, 0 1px #FFFFFF; color: #221919; display: block; font-size: 18px; line-height: 1.4em; padding: 6px 12px; position: relative; transition: all 0.08s ease-in-out 0s; width: 95%; z-index: 3; } .ctrl_grp input[type="text"]:focus, .ctrl_grp input[type="password"]:focus { border-color: ##993300; box-shadow: 0 1px rgba(34, 25, 25, 0.15) inset, 0 1px rgba(255, 255, 255, 0.8), 0 0 14px rgba(235, 82, 82, 0.35); } .ctrl_grp label { -moz-user-select: none; color: #EFEFEF; display: block; font-size: 18px; left: 13px; line-height: 1.4em; position: absolute; top: 5px; transition: all 0.16s ease-in-out 0s; z-index: 2; } .ctrl_grp .fff { background-color: #FFFFFF; border-radius: 8px 8px 8px 8px; bottom: 0; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .submit_button { background-image: -moz-linear-gradient(center top , #FDFAFB, #F9F7F7 50%, #F6F3F4 50%, #F0EDED); border: 1px solid #BBBBBB; border-radius: 6px 6px 6px 6px; box-shadow: 0 1px rgba(255, 255, 255, 0.8), 0 1px rgba(255, 255, 255, 0.35) inset; color: #524D4D; cursor: pointer; display: inline-block; font-family: "helvetica neue",arial,sans-serif; font-size: 18px; font-weight: bold; line-height: 1em; margin: 0; padding: 0.45em 0.825em; text-align: center; text-shadow: 0 1px rgba(255, 255, 255, 0.9); transition: all 0.05s ease-in-out 0s; } .submit_button:hover { box-shadow: 0 1px rgba(255, 255, 255, 0.8), 0 1px rgba(255, 255, 255, 0.35) inset, 0 0 10px rgba(232, 230, 230, 0.75); }
Live Demo
Conclusion
We have just finished our third lesson where we writing our own Pinterest-like script. I hope that you like it. It would be kind of you to share our materials with your friends. Good luck and welcome back!
i think this is the final touchdown :D
Great Tutorial ! i tried the local code ; accepting users works but i can’t seem to be able to upload images. Is there a custom setting I missed? Thanks for your support.
Hi cas,
I think that you could forget about permission to ‘photos’ table (should be 777)
Really guy i love you. You are the greatest.
Thanks man
Hi Admin, tIt wokrs now, thanks for the tip!
Looking forward to the next round. Cas
Greta tutorial, will be good to have one about how to do the database :)
How do I add the SQL part to my database?
Hi Sam,
Use phpMyAdmin -> SQL
Is there a way to add videos in addition to photos? How can I add this capability?
Hi Sam,
In fact, this is not so difficult, but it depends on your capabilities. Do you plan to work only with embed (youtube) videos, or you are going to upload and convert them? You just need to add this appropriate uploader.
I was looking to upload videos to the database.
Hi Sam,
You need to understand, that you can not upload videos (any files) directly into the database. Files can be uploaded only as files (to hosting), but not into the database. But you can keep the records in your database about all uploaded files.
If I wanted to allow users to upload videos to my website that would be hosted on Youtube, how would I do this? I looked for an uploader but couldn’t find anything.
Hi Sam,
The tutorial is about building photo service, not video.
When I test my website it says “Database query error”. What does this mean?
Hi Steve,
It can mean two things – first, that you forgot to put your db credentials (or put it wrongly), second, it means a certain SQL error.
How do you add a password confirmation field in the registration field?
Hello,
You can create a similar field (for the confirmation field) for the registration form (CMembers.php). And then, validate this field (if it has the same value as the ‘password’ field)