Have you thought about own facebook-style photo gallry system with comments? I have and today I prepared it for you. In this post i explained the easy way to create your Facebook style photo gallery with comments application. I used to create the ajax, php, and mysql as database to store the gallery details.
Create database table gallery
1 2 3 4 5 6 7 8 9 |
CREATE TABLE IF NOT EXISTS `gallery` ( `id` int(10) unsigned NOT NULL auto_increment, `title` varchar(255) default '', `filename` varchar(255) default '', `description` text 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 some example data
1 2 3 4 5 6 7 8 9 10 11 |
INSERT INTO `gallery` (`title`, `filename`, `description`, `when`) VALUES ('Item #1', 'photo1.jpg', 'Description of Item #1', UNIX_TIMESTAMP()), ('Item #2', 'photo2.jpg', 'Description of Item #2', UNIX_TIMESTAMP()+1), ('Item #3', 'photo3.jpg', 'Description of Item #3', UNIX_TIMESTAMP()+2), ('Item #4', 'photo4.jpg', 'Description of Item #4', UNIX_TIMESTAMP()+3), ('Item #5', 'photo5.jpg', 'Description of Item #5', UNIX_TIMESTAMP()+4), ('Item #6', 'photo6.jpg', 'Description of Item #6', UNIX_TIMESTAMP()+5), ('Item #7', 'photo7.jpg', 'Description of Item #7', UNIX_TIMESTAMP()+6), ('Item #8', 'photo8.jpg', 'Description of Item #8', UNIX_TIMESTAMP()+7), ('Item #9', 'photo9.jpg', 'Description of Item #9', UNIX_TIMESTAMP()+8), ('Item #10', 'photo10.jpg', 'Description of Item #10', UNIX_TIMESTAMP()+9); |
Create comments table
1 2 3 4 5 6 7 8 9 10 |
CREATE TABLE IF NOT EXISTS `comments` ( `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; |
Create index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php require('classes/CMySQL.php'); // include service classes to work with database and comments require('classes/CMyComments.php'); if ($_POST['action'] == 'accept_comment') { echo $GLOBALS['MyComments']->acceptComment(); exit; } // prepare a list with photos $sPhotos = ''; $aItems = $GLOBALS['MySQL']->getAll("SELECT * FROM `gallery` ORDER by `when` ASC"); // get photos info foreach ($aItems as $i => $aItemInfo) { $sPhotos .= '<div class="photo"><img src="images/thumb_'.$aItemInfo['filename'].'" id="'.$aItemInfo['id'].'" /><p>'.$aItemInfo['title'].' item</p><i>'.$aItemInfo['description'].'</i></div>'; } ?> <!DOCTYPE html> <html lang="en"><head> <meta charset="utf-8" /> <title>Facebook style photo gallery with comments By Freewebmentor</title> <!-- Link styles --> <link href="css/style.css" rel="stylesheet" type="text/css" /> <!-- Link scripts --> <script src="https://www.google.com/jsapi"></script> <script> google.load("jquery", "1.7.1"); </script> <script src="js/script.js"></script> </head> <body> <header> <h2>Facebook like photo gallery with comments</h2> <a href="http://freewebmentor.com/2014/10/facebook-style-photo-gallery-comments.html" class="stuts">Back to original tutorial</a> </header> <!-- Container with last photos --> <div class="container"> <h1>Last photos:</h1> <?= $sPhotos ?> </div> <!-- Hidden preview block --> <div id="photo_preview" style="display:none"> <div class="photo_wrp"> <img class="close" src="images/close.gif" /> <div style="clear:both"></div> <div class="pleft">test1</div> <div class="pright">test2</div> <div style="clear:both"></div> </div> </div> </body></html> |
Gallery_ajx.php page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php if ($_POST['action'] == 'get_info' && (int)$_POST['id'] > 0) { require_once('classes/CMySQL.php'); // include service classes to work with database and comments require_once('classes/Comments.php'); // get photo info $iPid = (int)$_POST['id']; $aImageInfo = $GLOBALS['MySQL']->getRow("SELECT * FROM `gallery` WHERE `id` = '{$iPid}'"); // prepare last 10 comments $sCommentsBlock = $GLOBALS['MyComments']->getComments($iPid); $aItems = $GLOBALS['MySQL']->getAll("SELECT * FROM `gallery` ORDER by `when` ASC"); // get photos info // Prev & Next navigation $sNext = $sPrev = ''; $iPrev = (int)$GLOBALS['MySQL']->getOne("SELECT `id` FROM `gallery` WHERE `id` < '{$iPid}' ORDER BY `id` DESC LIMIT 1"); $iNext = (int)$GLOBALS['MySQL']->getOne("SELECT `id` FROM `gallery` WHERE `id` > '{$iPid}' ORDER BY `id` ASC LIMIT 1"); $sPrevBtn = ($iPrev) ? '<div class="preview_prev" onclick="getPhotoPreviewAjx(\''.$iPrev.'\')"><img src="images/prev.png" alt="prev" /></div>' : ''; $sNextBtn = ($iNext) ? '<div class="preview_next" onclick="getPhotoPreviewAjx(\''.$iNext.'\')"><img src="images/next.png" alt="next" /></div>' : ''; require_once('classes/Services_JSON.php'); $oJson = new Services_JSON(); header('Content-Type:text/javascript'); echo $oJson->encode(array( 'data1' => '<img class="fileUnitSpacer" src="images/'. $aImageInfo['filename'] .'">' . $sPrevBtn . $sNextBtn, 'data2' => $sCommentsBlock, )); exit; } ?> |
Create classes/Comments.php page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
<?php class CMyComments { // constructor function CMyComments() { } // return comments block function getComments($i) { // draw last 10 comments $sComments = ''; $aComments = $GLOBALS['MySQL']->getAll("SELECT * FROM `comments` WHERE `c_item_id` = '{$i}' ORDER BY `c_when` DESC LIMIT 10"); foreach ($aComments as $i => $aCmtsInfo) { $sWhen = date('F j, Y H:i', $aCmtsInfo['c_when']); $sComments .= <<<EOF <div class="comment" id="{$aCmtsInfo['c_id']}"> <p>Comment from {$aCmtsInfo['c_name']} <span>({$sWhen})</span>:</p> <p>{$aCmtsInfo['c_text']}</p> </div> EOF; } return <<<EOF <div class="comments" id="comments"> <h2>Comments</h2> <div id="comments_warning1" style="display:none">Don`t forget to fill both fields (Name and Comment)</div> <div id="comments_warning2" style="display:none">You can't post more than one comment per 10 minutes (spam protection)</div> <form onsubmit="return false;"> <table> <tr><td class="label"><label>Your name: </label></td><td class="field"><input type="text" value="" title="Please enter your name" id="name" /></td></tr> <tr><td class="label"><label>Comment: </label></td><td class="field"><textarea name="text" id="text"></textarea></td></tr> <tr><td class="label"> </td><td class="field"><button onclick="submitComment({$i}); return false;">Post comment</button></td></tr> </table> </form> <div id="comments_list">{$sComments}</div> </div> EOF; } function acceptComment() { $iItemId = (int)$_POST['id']; // prepare necessary information $sIp = $this->getVisitorIP(); $sName = $GLOBALS['MySQL']->escape(strip_tags($_POST['name'])); $sText = $GLOBALS['MySQL']->escape(strip_tags($_POST['text'])); if ($sName && $sText) { // check - if there is any recent post from you or not $iOldId = $GLOBALS['MySQL']->getOne("SELECT `c_item_id` FROM `comments` WHERE `c_item_id` = '{$iItemId}' AND `c_ip` = '{$sIp}' AND `c_when` >= UNIX_TIMESTAMP() - 600 LIMIT 1"); if (! $iOldId) { // if everything is fine - allow to add comment $GLOBALS['MySQL']->res("INSERT INTO `comments` SET `c_item_id` = '{$iItemId}', `c_ip` = '{$sIp}', `c_when` = UNIX_TIMESTAMP(), `c_name` = '{$sName}', `c_text` = '{$sText}'"); $GLOBALS['MySQL']->res("UPDATE `gallery` SET `comments_count` = `comments_count` + 1 WHERE `id` = '{$iItemId}'"); // and print out last 10 comments $sOut = ''; $aComments = $GLOBALS['MySQL']->getAll("SELECT * FROM `comments` WHERE `c_item_id` = '{$iItemId}' ORDER BY `c_when` DESC LIMIT 10"); foreach ($aComments as $i => $aCmtsInfo) { $sWhen = date('F j, Y H:i', $aCmtsInfo['c_when']); $sOut .= <<<EOF <div class="comment" id="{$aCmtsInfo['c_id']}"> <p>Comment from {$aCmtsInfo['c_name']} <span>({$sWhen})</span>:</p> <p>{$aCmtsInfo['c_text']}</p> </div> EOF; } return $sOut; } } return 1; } // get visitor IP function getVisitorIP() { $ip = "0.0.0.0"; if( ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) && ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif( ( isset( $_SERVER['HTTP_CLIENT_IP'])) && (!empty($_SERVER['HTTP_CLIENT_IP'] ) ) ) { $ip = explode(".",$_SERVER['HTTP_CLIENT_IP']); $ip = $ip[3].".".$ip[2].".".$ip[1].".".$ip[0]; } elseif((!isset( $_SERVER['HTTP_X_FORWARDED_FOR'])) || (empty($_SERVER['HTTP_X_FORWARDED_FOR']))) { if ((!isset( $_SERVER['HTTP_CLIENT_IP'])) && (empty($_SERVER['HTTP_CLIENT_IP']))) { $ip = $_SERVER['REMOTE_ADDR']; } } return $ip; } } $GLOBALS['MyComments'] = new CMyComments(); ?> |
Javascript Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
<script type="text/javascript"> // close photo preview block function closePhotoPreview() { $('#photo_preview').hide(); $('#photo_preview .pleft').html('empty'); $('#photo_preview .pright').html('empty'); }; // display photo preview block function getPhotoPreviewAjx(id) { $.post('photos_ajx.php', {action: 'get_info', id: id}, function(data){ $('#photo_preview .pleft').html(data.data1); $('#photo_preview .pright').html(data.data2); $('#photo_preview').show(); }, "json" ); }; // submit comment function submitComment(id) { var sName = $('#name').val(); var sText = $('#text').val(); if (sName && sText) { $.post('index.php', { action: 'accept_comment', name: sName, text: sText, id: id }, function(data){ if (data != '1') { $('#comments_list').fadeOut(1000, function () { $(this).html(data); $(this).fadeIn(1000); }); } else { $('#comments_warning2').fadeIn(1000, function () { $(this).fadeOut(1000); }); } } ); } else { $('#comments_warning1').fadeIn(1000, function () { $(this).fadeOut(1000); }); } }; // init $(function(){ // onclick event handlers $('#photo_preview .photo_wrp').click(function (event) { event.preventDefault(); return false; }); $('#photo_preview').click(function (event) { closePhotoPreview(); }); $('#photo_preview img.close').click(function (event) { closePhotoPreview(); }); // display photo preview ajaxy $('.container .photo img').click(function (event) { if (event.preventDefault) event.preventDefault(); getPhotoPreviewAjx($(this).attr('id')); }); }) </script> |
Custom Css code for style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
/* project styles */ .container { border: 1px solid #111111; color: #000000; margin: 20px auto; overflow: hidden; padding: 15px; position: relative; text-align: center; width: 1090px; -moz-border-radius: 5px; -ms-border-radius: 5px; -o-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } .photo { border: 1px solid transparent; float: left; margin: 4px; overflow: hidden; padding: 4px; white-space: nowrap; /* CSS3 Box sizing property */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; /* CSS3 transition */ -moz-transition: border 0.2s ease 0s; -ms-transition: border 0.2s ease 0s; -o-transition: border 0.2s ease 0s; -webkit-transition: border 0.2s ease 0s; transition: border 0.2s ease 0s; } .photo:hover { border-color: #444; } .photo img { cursor: pointer; width: 200px; } .photo p, .photo i { display: block; } .photo p { font-weight: bold; } /* preview styles */ #photo_preview { background-color: rgba(0, 0, 0, 0.7); bottom: 0; color: #000000; display: none; left: 0; overflow: hidden; position: fixed; right: 0; top: 0; z-index: 10; } .photo_wrp { background-color: #FAFAFA; height: auto; margin: 100px auto 0; overflow: hidden; padding: 15px; text-align: center; vertical-align: middle; width: 1000px; -moz-border-radius: 5px; -ms-border-radius: 5px; -o-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } .close { cursor: pointer; float: right; } .pleft { float: left; overflow: hidden; position: relative; width: 600px; } .pright { float: right; position: relative; width: 360px; } .preview_prev, .preview_next { cursor: pointer; margin-top: -64px; opacity: 0.5; position: absolute; top: 50%; -moz-transition: opacity 0.2s ease 0s; -ms-transition: opacity 0.2s ease 0s; -o-transition: opacity 0.2s ease 0s; -webkit-transition: opacity 0.2s ease 0s; transition: opacity 0.2s ease 0s; } .preview_prev:hover, .preview_next:hover { opacity: 1; } .preview_prev { left: 20px; } .preview_next { right: 40px; } /* comments styles */ #comments form { margin: 10px 0; text-align: left; } #comments table td.label { color: #000; font-size: 13px; padding-right: 3px; text-align: right; width: 105px; } #comments table label { color: #000; font-size: 16px; font-weight: normal; vertical-align: middle; } #comments table td.field input, #comments table td.field textarea { border: 1px solid #96A6C5; font-family: Verdana,Arial,sans-serif; font-size: 16px; margin-top: 2px; padding: 6px; width: 250px; } #comments_list { margin: 10px 0; text-align: left; } #comments_list .comment { border-top: 1px solid #000; padding: 10px 0; } #comments_list .comment:first-child { border-top-width:0px; } #comments_list .comment span { font-size: 11px; } |
If you like FreeWebMentor and you would like to contribute, you can write an article and mail your article to [email protected] Your article will appear on the FreeWebMentor main page and help other developers.
Article Tags: Ajax, Facebook, Javasrcipt, PHP