Generate a URL Preview with PHP and jQuery (Preview a Link)
Many modern web applications have this feature where, when a user adds a URL to posts or comments, the application shows a rich preview of that URL. Learn how to fetch content from a URL to create such a preview box.

Showing a preview of a link to users can be useful to let them know about the link and what content that link contains before they visit it. This post demonstrates how to extract content from a URL using jQuery, AJAX, and PHP to create a link preview similar to social media and other websites. We will create the following files to implement this feature:
- index.html: Contains an HTML form that will allow users to submit a URL to create a preview.
- extract-contents.php: Contains the code to fetch the required data from the submitted URL.
- javascript.js: Contains the code to send an AJAX request to the
extract-contents.phpscript. - style.css: Contains all the CSS formatting for our HTML page and URL data preview box.
In our implementation, extract-contents.php will do the main job of extracting information from the submitted URL. A quick overview of this script is as follows:
- Prepare a regular expression to validate the URL that the user submitted.
- Validate the URL and fetch the URL content.
- Open a new DOM document and load the fetched content into the DOM.
- Search for the first image in the content, title, and description tags.
- Prepare the HTML preview container and return the response.
Create an HTML Form and Link Preview Container
We create an HTML page that contains a form with a URL input field and a submit button. When the user submits this form, we will send it to a server-side PHP script to retrieve information from the URL.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Generate a URL Preview with PHP and jQuery - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="css/style.css" />
<script src="js/jquery-3.1.1.min.js" type="text/javascript"></script>
<script src="js/javascript.js" type="text/javascript"></script>
</head>
<body>
<section class="section py-4">
<div class="container">
<div class="extract-wrapper">
<label>Enter an absolute URL like https://www.codestacked.info</label>
<form class="url-extract-form">
<div class="input-group">
<input type="url" class="form-control url-input" value="" required="required" placeholder="Enter a URL to extract contents" />
<button type="submit" class="btn btn-green">Extract</button>
</div>
<div class="loader">
<i class="fa fa-spinner fa-spin"></i>
</div>
</form>
<div class="content-wrapper" id="content-wrapper"></div>
</div>
</div>
</section>
</body>
</html>
Submit The Form with an AJAX Request
We prevent the default behavior of the form we created; instead, we send it via a jQuery AJAX request to our server-side PHP script.
javascript.js
$(document).ready(function () {
$(".url-extract-form").on("submit", function (e) {
e.preventDefault();
let url = $(".url-input").val();
$(".content-wrapper").hide();
if (url != '') {
$(".loader").fadeIn();
$.ajax({
url: "extract-contents.php",
type: "POST",
data: {
url: url
},
success: function (data) {
$(".content-wrapper").html(data).slideDown();
$(".loader").fadeOut();
}
});
}
});
});Extract Content From URL for Link Preview in PHP
Now, we write our main PHP script that validates the submitted URL and loads its HTML content to read meta tags from it. The script uses DOM and XPath to find title, description, and image tags/metadata. Then we generate a preview box from the information retrieved from the submitted URL. The new domxpath() will be used for accessing elements in the loaded DOM document using XPath queries.
- Create a regular expression to validate the submitted URL.
- If the URL is not valid, prepare and return an error response.
- Define title and description variables with empty values.
- Prepare an array of images in case no Open Graph image is found on the page; we will use the first image from the document.
- We then fetch the content from the URL.
- Open a new DOM document and load the content fetched from the URL.
- Loop through all images in the document and add them to the
$imagesarray. - Fetch the title from the URL and assign it to the
$titlevariable. First, fetch the Open Graph meta title; if it does not exist, then get the content of the document title tag. - Fetch the description from the URL and assign it to the
$descriptionvariable. First, fetch the open graph meta description; if it does not exist, then get the description from thetype="description"meta tag. - Fetch the image from the URL and set it to the
$imagevariable. First, fetch the Open Graph meta image; if it does not exist, then use the first image from the$imagesarray. - Finally, return the HTML link preview box as the response.
extract-contents.php
<?php
if (!empty($_POST)) {
$post = $_POST;
$url = strtolower(filter_var($post['url'], FILTER_SANITIZE_URL));
$url = str_starts_with($url, 'http') ? $url : 'https://' . $url;
// regular expression to validate url
$regex = '/^((https?|ftp):\/\/)(www\.)?[\w\-]+\.[a-z]{2,4}\/?[\w\/\-]*(\.[a-z]{2,4})?$/';
preg_match($regex, $url, $hostname);
// Check if the URL is a valid URL
if (preg_match($regex, $url)) {
// Get contents of url
$content = @file_get_contents($url);
// If failed to get contents show an error
if (!$content) {
die('<div class="error">Error parsing the submitted URL.</div>');
}
$title = $description = "";
$images_arr = [];
// Open new dom document object
$dom = new domDocument('1.0', 'UTF-8');
// Load url content to dom document object
@$dom->loadHTML($content);
// Get images from dom document
$images = $dom->getElementsByTagName('img');
// Loop through images and push them to images array
foreach ($images as $image) {
$src = parse_url($image->getAttribute('src'));
if ($src['path'])
$images_arr[] = $image->getAttribute('src');
}
// Open xpath object for current dom document
$xpath = new domxpath($dom);
$og_title = $xpath->query('//meta[@property="og:title"]');
$og_description = $xpath->query('//meta[@property="og:description"]');
$og_image = $xpath->query('//meta[@property="og:image"]');
$meta_description = @$xpath->query('//meta[@name="description"]');
$meta_title = @$xpath->query('//title');
// Prepare title of document
if ($og_title->length) {
$title = $og_title->item(0)->getAttribute('content');
} elseif ($meta_title->length) {
$title = $meta_title->item(0)->textContent;
}
// Prepare description of document
if ($og_description->length) {
$description = $og_description->item(0)->getAttribute('content');
} elseif ($meta_description->length) {
$description = $meta_description->item(0)->getAttribute('content');
}
// Prepare image of document
if ($og_image->length) {
$image = $og_image->item(0)->getAttribute('content');
} elseif ($meta_description->length) {
$image = reset($images_arr);
} ?>
<div class="url-info-box">
<?php
if (!empty($image)) {
// Handling the https urls for images
$image = (preg_match('/^(https?)/', $image)) || (preg_match('/^(\/\/)/', $image))
? $image
: $hostname[0] . $image;
list($width, $height) = getimagesize($image);
?>
<div class="image">
<img src="<?= $image; ?>" class="img-responsive" width="<?= $width; ?>" height="<?= $height; ?>"
alt=""/>
</div>
<?php } ?>
<div class="data">
<div class="title">
<?= $title; ?>
</div>
<div class="description"><?= $description; ?></div>
</div>
</div>
<?php
} else {
echo '<div class="error">Invalid URL submitted.</div>';
}
}
Add CSS Styles for Form, Loader, and Preview Container
We want specific styling for our interface and preview box. So we add CSS styles for the entire page, including the form input field, spinner, and URL preview container.
style.css
* {
box-sizing: border-box;
}
html,body {
margin: 0;
padding: 0;
}
body {
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.container {
max-width: 1024px;
margin: 0 auto;
padding-left: 15px;
padding-right: 15px;
}
.url-extract-form {
position: relative;
margin-bottom: 1rem;
}
.extract-wrapper label {
display: inline-block;
margin-bottom: 0.25rem;
}
.input-group {
position: relative;
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.form-control {
border: 1px solid #ddd;
padding: 10px;
position: relative;
font-size: inherit;
flex: 1 1 auto;
width: 1%;
min-width: 0;
}
.form-control:focus {
border-color: #00c0ef;
outline: 0;
}
.loader {
position: absolute;
inset: 0;
font-size: 1.75rem;
background: rgba(150,150,150,0.5);
z-index: 5;
padding: 0px 10px;
display: none;
color: #006699;
text-align: center;
}
.url-extract-form button {
display: inline-block;
padding: 5px 10px;
cursor: pointer;
font: inherit;
background: #00a65a;
border: 1px solid #009549;
color: #fff;
margin-left: -1px;
}
.content-wrapper .error {
padding: 10px;
background: #e95454;
color: #fff;
}
.url-info-box {
background: #fefefe;
border: 1px solid #fefefe;
overflow: hidden;
font-size: 13px;
max-width: 300px;
}
.img-responsive {
max-width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
.url-info-box .data {
padding: 15px;
background: #efefef;
}
.url-info-box .title {
font-weight: bold;
max-height: 35px;
overflow: hidden;
color: #3778cd;
}We demonstrated how to generate a link preview like many social media platforms with example code. The code snippets in this post can be extended for use in scraping tools to fetch meta tags and other elements of a web page.