How to create Pinterest-like script – step 3

By | June 3, 2014
0
0



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.

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:

<!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>

            <!-- logo -->
            <a href="#"></a>

            <!-- search form -->
            <form action="" method="get">
                <input autocomplete="off" name="q" size="27" placeholder="Search" type="text" />
                <input name="search" type="submit" />
            </form>

            <!-- navigation menu -->
            <ul>
                <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><a href="#">Careers</a></li>
                        <li><a href="#">Team</a></li>
                        <li><a href="#">Blog</a></li>
                        <li><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="http://www.script-tutorials.com/pinterest-like-script-step-3/">Back to tutorial</a>
                </li>
            </ul>

        </div>

        {extra_data}

        <!-- main container -->
        <div>
            {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>
    <div>
        <a href="#">Follow</a>
        <a target="_blank" href="#">
            <img alt="<?= $sOwnerName ?>" src="images/avatar.jpg" />
        </a>
        <p><a target="_blank" href="#"><?= $sOwnerName ?></a></p>
        <p>Uploaded on <?= $sPhotoDate ?></p>
    </div>
    <div>
        <div>
            <a href="#">Repin</a>
            <a href="#">Like</a>
        </div>
        <a href="#" title="<?= $sPhotoTitle ?>">
            <img alt="<?= $sPhotoTitle ?>" src="<?= $sFullImgPath ?>">
        </a>
    </div>

    <p><?= $sPhotoTitle ?></p>

    <div></div>

    <form method="post" action="#">
        <input type="hidden" name="id" value="0" />
        <textarea placeholder="Add a comment..." maxlength="1000"></textarea>
        <button type="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><a href="#">Boards</a></li>
        <li><a href="#">Pins</a></li>
        <li><a href="#">Likes</a></li>
        <li><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" id="add_form"></a>
<div>
    <div>
        <a 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" id="join_form"></a>
<div>
    <div>
        <a href="#close">x</a>
        <h2>Create your account</h2>
    </div>

    <form method="POST" action="service.php">
        <ul>
            <li>
                <input type="text" name="email" />
                <label>Email Address</label>
                <span></span>
            </li>
            <li>
                <input type="password" name="password" />
                <label>Password</label>
                <span></span>
            </li>
            <li>
                <input type="text" name="first_name" />
                <label>First Name</label>
                <span></span>
            </li>
            <li>
                <input type="text" name="last_name" />
                <label>Last Name</label>
                <span></span>
            </li>
        </ul>
        <div>
            <input type="hidden" name="Join" value="Join" />
            <button type="submit">Create Account</button>
        </div>
    </form>
</div>

<!-- login form -->
<a href="#x" id="login_form"></a>
<div>
    <div>
        <a href="#close">x</a>
        <h2>Login</h2>
    </div>

    <form method="POST" action="index.php">
        <ul>
            <li>
                <input type="text" name="email" id="id_email">
                <label>Email</label>
                <span></span>
            </li>
            <li>
                <input type="password" name="password" id="id_password">
                <label>Password</label>
                <span></span>
            </li>
        </ul>
        <div>
            <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>
    <div>
        <div pin_id="{$iPhotoId}">
            <a href="#">Repin</a>
            <a href="#">Like</a>
            <a href="#">Comment</a>
        </div>
        <a href="service.php?id={$iPhotoId}" title="{$sTitle}">
            <img alt="{$sTitle}" src="{$sFolder}{$sFile}">
        </a>
    </div>
    <p>{$sTitle}</p>
    <p>
        <span>XX likes</span>
        <span>XX repins</span>
    </p>
    <form method="post" action="" style="display: none">
        <input type="hidden" name="id" value="0" />
        <textarea placeholder="Add a comment..." maxlength="1000"></textarea>
        <button type="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);
}

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!

Leave a Reply

Your email address will not be published. Required fields are marked *