Anqi Chen 6 лет назад
Родитель
Сommit
2027d63b4a

+ 12 - 0
Yo/ajax/setBroken.php

@@ -0,0 +1,12 @@
+<?php
+include("../config.php");
+
+if(isset($_POST["src"])) {
+	$query = $con->prepare("UPDATE images SET broken = 1 WHERE imageUrl=:src");
+	$query->bindParam(":src", $_POST["src"]);
+
+	$query->execute();
+} else {
+	echo "No src passed to page";
+}
+?>

+ 12 - 0
Yo/ajax/updateImageCount.php

@@ -0,0 +1,12 @@
+<?php
+include("../config.php");
+
+if(isset($_POST["imageUrl"])) {
+	$query = $con->prepare("UPDATE images SET clicks = clicks + 1 WHERE imageUrl=:imageUrl");
+	$query->bindParam(":imageUrl", $_POST["imageUrl"]);
+
+	$query->execute();
+} else {
+	echo "No image URL passed to page";
+}
+?>

+ 12 - 0
Yo/ajax/updateLinkCount.php

@@ -0,0 +1,12 @@
+<?php
+include("../config.php");
+
+if(isset($_POST["linkId"])) {
+	$query = $con->prepare("UPDATE sites SET clicks = clicks + 1 WHERE id=:id");
+	$query->bindParam(":id", $_POST["linkId"]);
+
+	$query->execute();
+} else {
+	echo "No link passed to page";
+}
+?>

+ 270 - 0
Yo/assets/css/style.css

@@ -0,0 +1,270 @@
+* {
+	font-family: arial, sans-serif;
+	color: #545454;
+}
+
+html,
+body {
+	margin: 0;
+	height: 100%;
+}
+
+.wrapper {
+	display: flex;
+    flex-direction: column;
+    min-height: 100%;
+}
+
+.wrapper.indexPage {
+	justify-content: center;
+}
+
+.mainSection {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+}
+
+.mainSection .searchContainer {
+	margin-top: 20px;
+    width: 100%;
+}
+
+.mainSection .searchContainer form {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+}
+
+.searchContainer .searchButton {
+	color: #757575;
+    background-color: #f5f5f5;
+    border: none;
+    height: 36px;
+    width: 125px;
+    border-radius: 1px;
+    font-size: 13px;
+    font-weight: bold;
+    margin-top: 20px;
+    cursor: pointer;
+    outline: none;
+}
+
+.mainSection .searchContainer .searchBox {
+	border: none;
+    box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
+    height: 44px;
+    border-radius: 2px;
+    outline: none;
+    padding: 10px;
+    box-sizing: border-box;
+    font-size: 16px;
+    width: 70%;
+    max-width: 630px;
+    color: #000;
+}
+
+.mainSection .logoContainer {
+	width: 220px;
+	text-align: center;
+}
+
+.logoContainer img {
+	width: 100%;
+}
+
+.header {
+	background-color: #FAFAFA;
+	border-bottom: 1px solid #ebebeb;
+}
+
+.wrapper .headerContent {
+	display: flex;
+	align-items: center;
+}
+
+.headerContent .logoContainer {
+	width: 150px;
+	padding: 5px 20px;
+	box-sizing: border-box;
+}
+
+.headerContent .searchContainer {
+	flex: 1;
+}
+
+.headerContent .searchContainer form {
+	margin: 15px 0 28px 0;
+}
+
+.headerContent .searchBarContainer {
+	height: 44px;
+	border-radius: 2px;
+	background-color: #fff;
+	box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
+	width: 70%;
+	max-width: 630px;
+	box-sizing: border-box;
+	display: flex;
+}
+
+.headerContent .searchBarContainer .searchBox {
+	flex: 1;
+	border: none;
+    background-color: transparent;
+    outline-color: #D0021B;
+	padding: 12px;
+	font-size: 16px;
+	color: #000;
+}
+
+.headerContent .searchBarContainer .searchButton {
+	background-color: #fff;
+	height: 44px;
+	margin-top: 0;
+	width: 44px;
+	padding-right: 20px;
+	display: flex;
+	justify-content: center;
+}
+
+.headerContent .searchBarContainer .searchButton img {
+	width: 22px
+}
+
+.tabsContainer {
+	margin-left: 150px;
+}
+
+.tabsContainer .tabList {
+	padding: 0;
+	margin: 0;
+}
+
+.tabsContainer .tabList li {
+	display: inline-block;
+	padding: 0 16px 12px 16px;
+	color: #777;
+	font-size: 13px;
+}
+
+.tabsContainer .tabList li a {
+	text-decoration: none;
+}
+
+.tabsContainer .tabList li.active {
+	border-bottom: 3px solid #D0021B;
+}
+
+.tabsContainer .tabList li.active a {
+	font-weight: bold;
+	color: #D0021B;
+}
+
+.mainResultsSection {
+	flex: 1;
+}
+
+.mainResultsSection .resultsCount {
+	font-size: 13px;
+	color: #808080;
+	margin-left: 150px;
+}
+
+.mainResultsSection .siteResults {
+	margin-left: 150px;
+}
+
+.resultContainer {
+	display: flex;
+	flex-direction: column;
+	margin-bottom: 26px;
+}
+
+.resultContainer .title {
+	margin: 0;
+}
+
+.resultContainer .title a {
+	color: #1a0dab;
+	text-decoration: none;
+	font-weight: normal;
+	font-size: 18px;
+}
+
+.resultContainer .title a:hover {
+	text-decoration: underline;
+}
+
+.resultContainer .url {
+	color: #006621;
+	font-size: 14px;
+}
+
+.resultContainer .description {
+	font-size: 12px;
+}
+
+.paginationContainer {
+	display: flex;
+	justify-content: center;
+	margin-bottom: 25px;
+}
+
+.pageButtons {
+	display: flex;
+}
+
+.pageNumberContainer img {
+	height: 37px;
+}
+
+.pageNumberContainer,
+.pageNumberContainer a {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	text-decoration: none;
+}
+
+.pageNumber {
+	color: #000;
+	font-size: 13px;
+}
+
+a .pageNumber {
+	color: #D0021B;
+}
+
+.mainResultsSection .imageResults {
+	margin: 20px;
+}
+
+.gridItem {
+	position: relative;
+}
+
+.gridItem img {
+	max-width: 200px;
+	min-width: 50px;
+	visibility: hidden;
+}
+
+.gridItem .details {
+	visibility: hidden;
+	position: absolute;
+	bottom: 0px;
+	left: 0px;
+	width: 100%;
+	overflow: hidden;
+	background-color: rgba(0,0,0,0.8);
+	color: #fff;
+	font-size: 11px;
+	padding: 3px;
+	box-sizing: border-box;
+	white-space: nowrap;
+}
+
+.gridItem:hover .details {
+	visibility: visible;
+} 

BIN
Yo/assets/images/icons/search.png


BIN
Yo/assets/images/logo.png


BIN
Yo/assets/images/page.png


BIN
Yo/assets/images/pageEnd.png


BIN
Yo/assets/images/pageSelected.png


BIN
Yo/assets/images/pageStart.png


+ 90 - 0
Yo/assets/js/script.js

@@ -0,0 +1,90 @@
+var timer;
+
+$(document).ready(function() {
+    $(".result").on("click", function() {
+		var id = $(this).attr("data-linkId");
+		var url = $(this).attr("href");
+
+		if(!id) {
+			alert("data-linkId attribute not found");
+		}
+
+		increaseLinkClicks(id, url);
+
+		return false;
+	});
+
+	var grid = $(".imageResults");
+
+	grid.on("layoutComplete", function() {
+		$(".gridItem img").css("visibility", "visible");
+	});
+
+	grid.masonry({
+		itemSelector: ".gridItem",
+		columnWidth: 200,
+		gutter: 5,
+		isInitLayout: false
+	});
+
+	$("[data-fancybox]").fancybox({
+		caption : function( instance, item ) {
+			var caption = $(this).data('caption') || '';
+			var siteUrl = $(this).data('siteurl') || '';
+
+			if ( item.type === 'image' ) {
+					caption = (caption.length ? caption + '<br />' : '')
+					 + '<a href="' + item.src + '">View image</a><br>'
+					 + '<a href="' + siteUrl + '">Visit page</a>';
+			}
+
+			return caption;
+		},
+		afterShow : function( instance, item ) {
+			increaseImageClicks(item.src);
+		}
+	});
+});
+
+function loadImage(src, className) {
+	var image = $("<img>");
+
+	image.on("load", function() {
+		$("." + className + " a").append(image);
+
+		clearTimeout(timer);
+
+		timer = setTimeout(function() {
+			$(".imageResults").masonry();
+		}, 500);
+	});
+
+	image.on("error", function() {
+		$("." + className).remove();
+
+		$.post("ajax/setBroken.php", {src: src});
+	});
+
+	image.attr("src", src);
+}
+
+function increaseLinkClicks(linkId, url) {
+	$.post("ajax/updateLinkCount.php", {linkId: linkId})
+	.done(function(result) {
+		if(result != "") {
+			alert(result);
+			return;
+		}
+		window.location.href = url;
+	});
+}
+
+function increaseImageClicks(imageUrl) {
+	$.post("ajax/updateImageCount.php", {imageUrl: imageUrl})
+	.done(function(result) {
+		if(result != "") {
+			alert(result);
+			return;
+		}
+	});
+}

+ 31 - 0
Yo/classes/DomDocumentParser.php

@@ -0,0 +1,31 @@
+<?php
+    class DomDocumentParser {
+        private $doc;
+    
+        public function __construct($url) {
+            $options = array(
+                'http'=>array('method'=>"GET", 'header'=>"User-Agent: YoBot/0.1\n")
+                );
+            $context = stream_context_create($options);
+    
+            $this->doc = new DomDocument();
+            @$this->doc->loadHTML(file_get_contents($url, false, $context));
+        }
+    
+        public function getlinks() {
+            return $this->doc->getElementsByTagName("a");
+        }
+    
+        public function getTitleTags() {
+            return $this->doc->getElementsByTagName("title");
+        }
+    
+        public function getMetaTags() {
+            return $this->doc->getElementsByTagName("meta");
+        }
+    
+        public function getImages() {
+            return $this->doc->getElementsByTagName("img");
+        }
+    }
+?>

+ 79 - 0
Yo/classes/ImageResultsProvider.php

@@ -0,0 +1,79 @@
+<?php
+class ImageResultsProvider {
+	private $con;
+
+	public function __construct($con) {
+		$this->con = $con;
+	}
+
+	public function getNumResults($term) {
+		$query = $this->con->prepare("SELECT COUNT(*) as total 
+										 FROM images 
+										 WHERE (title LIKE :term 
+										 OR alt LIKE :term)
+                                         AND broken=0");
+                                         
+		$searchTerm = "%". $term . "%";
+		$query->bindParam(":term", $searchTerm);
+		$query->execute();
+
+		$row = $query->fetch(PDO::FETCH_ASSOC);
+		return $row["total"];
+    }
+
+    public function getResultsHtml($page, $pageSize, $term) {
+
+		$fromLimit = ($page - 1) * $pageSize;
+
+		$query = $this->con->prepare("SELECT * 
+										 FROM images 
+										 WHERE (title LIKE :term 
+										 OR alt LIKE :term)
+										 AND broken=0
+										 ORDER BY clicks DESC
+										 LIMIT :fromLimit, :pageSize");
+
+		$searchTerm = "%". $term . "%";
+		$query->bindParam(":term", $searchTerm);
+		$query->bindParam(":fromLimit", $fromLimit, PDO::PARAM_INT);
+		$query->bindParam(":pageSize", $pageSize, PDO::PARAM_INT);
+		$query->execute();
+
+		$resultsHtml = "<div class='imageResults'>";
+
+        $count = 0;
+		while($row = $query->fetch(PDO::FETCH_ASSOC)) {
+            $count++;
+            $id = $row["id"];
+			$imageUrl = $row["imageUrl"];
+			$siteUrl = $row["siteUrl"];
+			$title = $row["title"];
+            $alt = $row["alt"];
+            
+            if($title) {
+				$displayText = $title;
+			} else if($alt) {
+				$displayText = $alt;
+			} else {
+				$displayText = $imageUrl;
+            }		
+            
+			$resultsHtml .= "<div class='gridItem image$count'>
+                                <a href='$imageUrl' data-fancybox data-caption='$displayText' data-siteurl='$siteUrl'>
+                                    
+                                    <script>
+                                    $(document).ready(function() {
+                                        loadImage(\"$imageUrl\",\"image$count\");
+                                    });
+                                    </script>
+
+                                    <span class='details'>$displayText</span>
+                                </a>
+							</div>";
+		}
+		$resultsHtml .= "</div>";
+
+		return $resultsHtml;
+    }
+}
+?>

+ 73 - 0
Yo/classes/SiteResultsProvider.php

@@ -0,0 +1,73 @@
+<?php
+class SiteResultsProvider {
+	private $con;
+
+	public function __construct($con) {
+		$this->con = $con;
+	}
+
+	public function getNumResults($term) {
+		$query = $this->con->prepare("SELECT COUNT(*) as total 
+										 FROM sites WHERE title LIKE :term 
+										 OR url LIKE :term 
+										 OR keywords LIKE :term 
+										 OR description LIKE :term");
+
+		$searchTerm = "%". $term . "%";
+		$query->bindParam(":term", $searchTerm);
+		$query->execute();
+
+		$row = $query->fetch(PDO::FETCH_ASSOC);
+		return $row["total"];
+    }
+
+    public function getResultsHtml($page, $pageSize, $term) {
+
+		$fromLimit = ($page - 1) * $pageSize;
+
+		$query = $this->con->prepare("SELECT * 
+										 FROM sites WHERE title LIKE :term 
+										 OR url LIKE :term 
+										 OR keywords LIKE :term 
+										 OR description LIKE :term
+										 ORDER BY clicks DESC
+										 LIMIT :fromLimit, :pageSize");
+
+		$searchTerm = "%". $term . "%";
+		$query->bindParam(":term", $searchTerm);
+		$query->bindParam(":fromLimit", $fromLimit, PDO::PARAM_INT);
+		$query->bindParam(":pageSize", $pageSize, PDO::PARAM_INT);
+		$query->execute();
+
+		$resultsHtml = "<div class='siteResults'>";
+
+		while($row = $query->fetch(PDO::FETCH_ASSOC)) {
+			$id = $row["id"];
+			$url = $row["url"];
+			$title = $row["title"];
+			$description = $row["description"];
+			$title = $this->trimField($title, 55);
+			$description = $this->trimField($description, 230);			
+			$resultsHtml .= "<div class='resultContainer'>
+
+								<h3 class='title'>
+									<a class='result' href='$url' data-linkId='$id'>
+										$title
+									</a>
+								</h3>
+								<span class='url'>$url</span>
+								<span class='description'>$description</span>
+
+							</div>";
+		}
+		$resultsHtml .= "</div>";
+
+		return $resultsHtml;
+    }
+    
+    private function trimField($string, $characterLimit) {
+		$dots = strlen($string) > $characterLimit ? "..." : "";
+		return substr($string, 0, $characterLimit) . $dots;
+	}
+}
+?>

+ 10 - 0
Yo/config.php

@@ -0,0 +1,10 @@
+<?php
+ob_start();
+
+try {
+	$con = new PDO("mysql:dbname=yo;host=localhost", "root", "");
+	$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+} catch(PDOExeption $e) {
+	echo "Connection failed: " . $e->getMessage();
+}
+?>

+ 162 - 0
Yo/crawl.php

@@ -0,0 +1,162 @@
+<?php
+include("config.php");
+include("classes/DomDocumentParser.php");
+
+$alreadyCrawled = array();
+$crawling = array();
+$alreadyFoundImages = array();
+
+function linkExists($url) {
+	global $con;
+
+	$query = $con->prepare("SELECT * FROM sites WHERE url = :url");
+
+	$query->bindParam(":url", $url);
+	$query->execute();
+
+	return $query->rowCount() != 0;
+}
+
+function insertLink($url, $title, $description, $keywords) {
+	global $con;
+
+	$query = $con->prepare("INSERT INTO sites(url, title, description, keywords)
+							VALUES(:url, :title, :description, :keywords)");
+
+	$query->bindParam(":url", $url);
+	$query->bindParam(":title", $title);
+	$query->bindParam(":description", $description);
+	$query->bindParam(":keywords", $keywords);
+
+	return $query->execute();
+}
+
+function insertImage($url, $src, $alt, $title) {
+	global $con;
+
+	$query = $con->prepare("INSERT INTO images(siteUrl, imageUrl, alt, title)
+							VALUES(:siteUrl, :imageUrl, :alt, :title)");
+
+	$query->bindParam(":siteUrl", $url);
+	$query->bindParam(":imageUrl", $src);
+	$query->bindParam(":alt", $alt);
+	$query->bindParam(":title", $title);
+
+	return $query->execute();
+}
+
+function createLink($src, $url) {
+	$scheme = parse_url($url)["scheme"]; // http
+	$host = parse_url($url)["host"]; // www.wsj.com
+	
+	if(substr($src, 0, 2) == "//") {
+		$src =  $scheme . ":" . $src;
+	} else if(substr($src, 0, 1) == "/") {
+		$src = $scheme . "://" . $host . $src;
+	} else if(substr($src, 0, 2) == "./") {
+		$src = $scheme . "://" . $host . dirname(parse_url($url)["path"]) . substr($src, 1);
+	} else if(substr($src, 0, 3) == "../") {
+		$src = $scheme . "://" . $host . "/" . $src;
+	} else if(substr($src, 0, 5) != "https" && substr($src, 0, 4) != "http") {
+		$src = $scheme . "://" . $host . "/" . $src;
+	}
+
+	return $src;
+}
+
+function getDetails($url) {
+	global $alreadyFoundImages;
+	$parser = new DomDocumentParser($url);
+	$titleArray = $parser->getTitleTags();
+
+	if(sizeof($titleArray) == 0 || $titleArray->item(0) == NULL) {
+		return;
+	}
+
+	$title = $titleArray->item(0)->nodeValue;
+	$title = str_replace("\n", "", $title);
+
+	if($title == "") {
+		return;
+	}
+
+	$description = "";
+	$keywords = "";
+
+	$metasArray = $parser->getMetatags();
+
+	foreach($metasArray as $meta) {
+		if($meta->getAttribute("name") == "description") {
+			$description = $meta->getAttribute("content");
+		}
+		if($meta->getAttribute("name") == "keywords") {
+			$keywords = $meta->getAttribute("content");
+		}
+	}
+
+	$description = str_replace("\n", "", $description);
+	$keywords = str_replace("\n", "", $keywords);
+
+	if(linkExists($url)) {
+		echo "$url already exists<br>";
+	} else if(insertLink($url, $title, $description, $keywords)) {
+		echo "SUCCESS: $url<br>";
+	} else {
+		echo "ERROR: Failed to insert $url<br>";
+	}
+
+	$imageArray = $parser->getImages();
+	foreach($imageArray as $image) {
+		$src = $image->getAttribute("src");
+		$alt = $image->getAttribute("alt");
+		$title = $image->getAttribute("title");
+
+		if(!$title && !$alt) {
+			continue;
+		}
+
+		$src = createLink($src, $url);
+
+		if(!in_array($src, $alreadyFoundImages)) {
+			$alreadyFoundImages[] = $src;
+            // insert the image
+			echo "INSERT: " . insertImage($url, $src, $alt, $title);
+		}
+	}
+}
+
+function followLinks($url) {
+	global $alreadyCrawled;
+	global $crawling;
+	$parser = new DomDocumentParser($url);
+	$linkList = $parser->getLinks();
+
+	foreach($linkList as $link) {
+		$href = $link->getAttribute("href");
+
+		if(strpos($href, "#") !== false) {
+			continue;
+		} else if(substr($href, 0, 11) == "javascript:") {
+			continue;
+		}
+
+		$href = createLink($href, $url);
+
+		if(!in_array($href, $alreadyCrawled)) {
+			$alreadyCrawled[] = $href;
+			$crawling[] = $href;
+
+			getDetails($href);
+		}
+	}
+
+	array_shift($crawling);
+
+	foreach($crawling as $site) {
+		followLinks($site);
+	}
+}
+
+$startUrl = "https://www.wsj.com/";
+followLinks($startUrl);
+?>

+ 36 - 0
Yo/index.php

@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title>Yo!</title>
+
+	<meta name="description" content="Search the web for sites and images.">
+	<meta name="keywords" content="Search engine, yo, websites">
+	<meta name="author" content="Anqi Chen">
+	<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+	<link rel="stylesheet" type="text/css" href="assets/css/style.css">
+
+</head>
+<body>
+
+	<div class="wrapper indexPage">
+	
+		<div class="mainSection">
+			<div class="logoContainer">
+				<img src="assets/images/logo.png" title="Logo of our site" alt="Site logo">
+			</div>
+
+			<div class="searchContainer">
+				<form action="search.php" method="GET">
+
+					<input class="searchBox" type="text" name="term" placeholder="Yo! What's up today?">
+					<input class="searchButton" type="submit" value="Search">
+
+				</form>
+			</div>
+		</div>
+
+	</div>
+
+</body>
+</html>

+ 157 - 0
Yo/search.php

@@ -0,0 +1,157 @@
+<?php
+include("config.php");
+include("classes/SiteResultsProvider.php");
+include("classes/ImageResultsProvider.php");
+
+if(isset($_GET["term"])) {
+	$term = $_GET["term"];
+} else {
+	exit("A search term is required");
+}
+
+$type = isset($_GET["type"]) ? $_GET["type"] : "sites";
+$page = isset($_GET["page"]) ? $_GET["page"] : 1;
+?>
+
+<!DOCTYPE html>
+<html>
+<head>
+	<title>Yo!What's up?</title>
+
+	<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
+	<link rel="stylesheet" type="text/css" href="assets/css/style.css">
+
+	<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
+</head>
+<body>
+	<div class="wrapper">
+        
+        <div class="header">
+
+			<div class="headerContent">
+
+				<div class="logoContainer">
+					<a href="index.php">
+						<img src="assets/images/logo.png">
+					</a>
+				</div>
+
+				<div class="searchContainer">
+                    
+                    <form action="search.php" method="GET">
+                        
+                        <div class="searchBarContainer">
+							<input type="hidden" name="type" value="<?php echo $type; ?>">
+							<input class="searchBox" type="text" name="term" value="<?php echo $term; ?>">
+							<button class="searchButton">
+								<img src="assets/images/icons/search.png">
+							</button>
+						</div>
+
+					</form>
+
+				</div>
+
+			</div>
+
+
+			<div class="tabsContainer">
+
+				<ul class="tabList">
+
+					<li class="<?php echo $type == 'sites' ? 'active' : '' ?>">
+						<a href='<?php echo "search.php?term=$term&type=sites"; ?>'>
+							Sites
+						</a>
+					</li>
+
+					<li class="<?php echo $type == 'images' ? 'active' : '' ?>">
+						<a href='<?php echo "search.php?term=$term&type=images"; ?>'>
+							Images
+						</a>
+					</li>
+
+				</ul>
+
+
+			</div>
+		</div>
+
+		<div class="mainResultsSection">
+			
+			<?php
+				if($type == "sites") {
+					$resultsProvider = new SiteResultsProvider($con);
+					$pageSize = 20;
+				} else {
+					$resultsProvider = new ImageResultsProvider($con);
+					$pageSize = 30;
+				}
+
+				$numResults = $resultsProvider->getNumResults($term);
+				
+				echo "<p class='resultsCount'>$numResults results found</p>";
+				echo $resultsProvider->getResultsHtml($page, $pageSize, $term);
+			?>
+
+		</div>
+
+		<div class="paginationContainer">
+
+			<div class="pageButtons">
+
+				<div class="pageNumberContainer">
+					<img src="assets/images/pageStart.png">
+				</div>
+
+				<?php
+
+					$pagesToShow = 10;
+					$numPages = ceil($numResults / $pageSize);
+					$pagesLeft = min($pagesToShow, $numPages);
+
+					$currentPage = $page - floor($pagesToShow / 2);
+
+					if($currentPage < 1) {
+						$currentPage = 1;
+					}
+
+					if($currentPage + $pagesLeft > $numPages + 1) {
+						$currentPage = $numPages + 1 - $pagesLeft;
+					}
+
+					while($pagesLeft != 0 && $currentPage <= $numPages) {
+
+						if($currentPage == $page) {
+							echo "<div class='pageNumberContainer'>
+									<img src='assets/images/pageSelected.png'>
+									<span class='pageNumber'>$currentPage</span>
+								</div>";
+						}
+						else {
+							echo "<div class='pageNumberContainer'>
+									<a href='search.php?term=$term&type=$type&page=$currentPage'>
+										<img src='assets/images/page.png'>
+										<span class='pageNumber'>$currentPage</span>
+									</a>
+							</div>";
+						}
+
+
+						$currentPage++;
+						$pagesLeft--;
+
+					}
+				?>	
+
+				<div class="pageNumberContainer">
+					<img src="assets/images/pageEnd.png">
+				</div>
+
+			</div>
+		</div>
+		<script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>
+		<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
+		<script type="text/javascript" src="assets/js/script.js"></script>
+</body>
+</html>