Check if a remote site is online using AJAX? - javascript

My site checks 5 different URLs using PHP's cURL to tell if they're online. The problem is that it takes too long to load the page (especially if one of the sites it's checking is down).
I hear jQuery's ajax would work well, so I tried this code:
<div class="alert alert-info" id="forum-blockland-us"><b>Checking...</b></div>
<script>
$.ajax({ type: "GET",
url: "http://forum.blockland.us/",
cache:false,
success: function() {
$("#forum-blockland-us").addClass("alert-success");
$("#forum-blockland-us").removeClass("alert-info");
$("#forum-blockland-us").html("<b>Online</b>");
},
error: function() {
$("#forum-blockland-us").addClass("alert-danger");
$("#forum-blockland-us").removeClass("alert-info");
$("#forum-blockland-us").html("<b>Offline</b>");
}
});
</script>
But it always returns the error, even when I know 100% that the sites are online.

If the site is remote, there are many chances you won't be able to achieve it with javascript due to the Same Origin Policy.
However, in php, you could make only a HEAD request so it doesn't load contents so it will be much, much faster.
Hope this helps. Cheers

As #Edgar said, you better do it by php, and if you want to, this is how :
function urlExists($url=NULL)
{
if($url == NULL) return false;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($httpcode>=200 && $httpcode<300){
return true;
} else {
return false;
}
}
Source

Related

Email submit through Mailchimp returning error, Javascript and php

I am hoping this is a simple issue. I am using the Mailchimp API to submit a simple email signup form from my website. I am trying to learn javascript right now, so I am trying to do the httprequest and callback without jQuery. Basically, I am trying to convert this jQuery sample I found online to vanilla Javascript. But there is something (several things?) wrong with my javascript that I don't understand.
EDIT: When the form is submitted, I am taken to the email-validate.php page, and show the following error object returned by MailChimp.
{"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/","title":"Invalid Resource","status":400,"detail":"The resource submitted could not be validated. For field-specific details, see the 'errors' array.","instance":"","errors":[{"field":"","message":"Required fields were not provided: email_address"},{"field":"email_address","message":"Schema describes string, NULL found instead"}]}
jQuery
Found here (this actually throws an ajax(...).success is not a function error in the console but still submits the form, FWIW)
$('document').ready(function(){
$('.mc-form').submit(function(e){
//prevent the form from submitting via the browser redirect
e.preventDefault();
//grab attributes and values out of the form
var data = {email: $('#mc-email').val()};
var endpoint = $(this).attr('action');
//make the ajax request
$.ajax({
method: 'POST',
dataType: "json",
url: endpoint,
data: data
}).success(function(data){
if(data.id){
//successful adds will have an id attribute on the object
alert('thanks for signing up');
} else if (data.title == 'Member Exists') {
//MC wil send back an error object with "Member Exists" as the title
alert('thanks, but you are alredy signed up');
} else {
//something went wrong with the API call
alert('oh no, there has been a problem');
}
}).error(function(){
//the AJAX function returned a non-200, probably a server problem
alert('oh no, there has been a problem');
});
});
});
My Javascript (that doesn't work)
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("mc-form", function submit(e){
e.preventDefault();
var data = {"email": document.getElementById("mc-email").value};
var endpoint = document.getElementById("mc-form").getAttribute('action');
function formSubmit(callback){
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
//Parse returned string into an object, then pass the object to the callback function.
var response = JSON.parse(request.responseText);
callback(response);
} else {
console.log('JSON request error');
}
}
}
request.open("POST", endpoint , true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(data);
}
function formResponse(response){
if(response.id){
//successful adds will have an id attribute on the object
alert('Thank you for signing up for Launch Alerts!');
} else if (response.title == 'Member Exists') {
//MC wil send back an error object with "Member Exists" as the title
alert('You are already signed up for Launch Alerts!');
} else {
//something went wrong with the API call
alert('Something went wrong. Please resubmit the form!');
}
}
formSubmit(formResponse);
})
});
My html
<form class="mc-form" method="POST" action="./email-validate.php">
<h2 class="launch-alerts">Never miss a launch with Launch Alerts</h2>
<label for="mc-email">Email Address:</label>
<input type="email" id="mc-email" name="mc-email" autofocus="true" required/>
<input type="text" value="pending" id="status" name="status" hidden/>
<input type="submit" value="Submit">
</form>
It uses a php file to validate and submit the form, as can be seen on the link above. The html and php work to submit the form when using the jQuery script, but not my javascript, which means there is something wrong with my script, but I am too new with javascript to fully understand what it is I am trying to do, and what I am doing wrong.
Thanks!
EDIT 2:
The PHP code (copied directly from here
<?php
//fill in these values for with your own information
$api_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$datacenter = 'xxxxx';
$list_id = 'xxxxxxxxx';
$email = $_POST['email'];
$status = 'pending';
if(!empty($_POST['status'])){
$status = $_POST['status'];
}
$url = 'https://'.$datacenter.'.api.mailchimp.com/3.0/lists/'.$list_id.'/members/';
$username = 'apikey';
$password = $api_key;
$data = array("email_address" => $email,"status" => $status);
$data_string = json_encode($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$api_key");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
$result=curl_exec ($ch);
curl_close ($ch);
echo $result;
?>
The data argument to request.send() must be a URL-encoded string, you're passing an object. jQuery does this conversion automatically for you; when you do it yourself, you have to do that yourself as well.
var data = "email=" + encodeURIComponent(document.getElementById("mc-email").value);
You're also not adding your submission function to the form's submit event correctly. It should be:
document.getElementById("mc-form").addEventListener("submit", function submit(e){
You can add URL Parameters manually to the URL:
var endpoint = document.getElementById("mc-form").getAttribute('action') +
"?email=" + document.getElementById("mc-email").value;
And then only do
request.send();
without the data in it.

AJAX Javascript Element not updating

I have an issue with the Internet Explorer/EDGE browser. Basically, I have a script that pulls data from a remote XML file and displays it in page (live example: http://www.oldiesplus.com/ - The Radio info section, top of the page)
The way it works is that every 15 seconds, the XML file is read and the Song Title is updated (that's the scrolling bit). This works perfectly in Google Chrome, under IE/EDGE, however, the script executes (see Console log) but the element is never updated.
The XML file is grabbed using Curl and CURLOPT_FRESH_CONTENT is set to true.
The question being then, why is the element not updating with the new content in IE/EDGE?
Here's some code to help:
sc_conn.inc (PHP):
$ch = curl_init($sc_host . '/admin.cgi?mode=viewxml');
curl_setopt($ch, CURLOPT_PORT, $sc_port);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $sc_admin.':'.$sc_pass);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
$curl = curl_exec($ch);
shoutcast.js (JavaScript):
function getStreamData() {
var ajax;
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
} else {
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
ajax.open('GET','/sc_data.php', true);
ajax.send();
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
var data = ajax.responseText.split("|");
var song = (data[1] == '') ? 'some music.' : data[1];
var cta = (player_state == 0) ? '/new/img/play.png' : '/new/img/pause.png';
if (data[2]) {
document.getElementById('radio-info').innerHTML = '<h2>'+data[2]+'</h2>';
document.getElementById('radio-info').innerHTML += '<p><span class="dj_name">'+data[0]+' is playing</span> '+song+'</p>';
}else{
document.getElementById('radio-info').innerHTML = '<p><span class="dj_name">'+data[0]+' is playing</span> '+song+'</p>';
}
document.getElementById('tunein').src = cta;
console.log("Title Updated!");
}
}
}
The resolution was to circumvent caching of the AJAX request - appending a random number to the end of the call of the PHP script using:
Math.random();

Secure ajax GET/POST request for server

suppose I work with some kind of API and my file server.php handles the connection to the API service. on my client side I use AJAX call like this:
$http({
url : 'server/server.php',
method : 'GET',
data : { getContent : true }
});
in my server.php I handle it like this:
if(isset($_GET['getContent'])){
$content = get_content();
}
function get_content(){...}
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data? how can i secure it and make sure only calls from my application will get the relevant data back?
thank you!
I guess you are concerned about CSRF attacks. Read more about this here: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
One of the mostly used option to secure your request will be:
- Generate a token and send it with the request for a session. This token can be identified by your WebServer as originating from a specific client for a specific session
2022 Update
This is a 7 year old post and the link in the link-only "accepted" answer is broken.
So, I'm going to offer a basic walkthrough and a complete model.
Remember, the $_SESSION will be preserved even in the AJAX handler, if it's all from the same domain. So, you can use that to check things.
Use $_POST
I presume you're using $_POST and not $_GET since you're concerned about security. If not, then much of this might not be important anyway.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$post_method = true;
}
Ensure the $_SERVER['HTTP_REFERER'] is from your own site
if ( (!empty($_SERVER['HTTP_REFERER']))
&& ($_SERVER['HTTP_REFERER'] === "https://example.tld/my_sending_page.php") ) {
$from_my_server = true;
}
If you're not sure what this should be, run a test on your own server to see what this should be:
echo $_SERVER['HTTP_REFERER'];
Verify XMLHTTP/AJAX request via $_SERVER array
if ( (!empty($_SERVER['HTTP_X_REQUESTED_WITH']))
&& ( strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') ) {
$ajax = true;
} else {
$ajax = false;
}
Use a token
This is the hard part, but not too hard.
Create the token
Set the token in $_SESSION
Put the token in the AJAX header
AJAX responder: confirm the AJAX header token with the $_SESSION token
send_from_me.php
// Create the token
//$token = md5(rand(10000,99999)); // Not recommended, but possible
$token = bin2hex(random_bytes(64));
// Store in SESSION
$_SESSION["token"] = $token;
// Assuming your AJAX is this
const AJAX = new XMLHttpRequest();
// This goes inside your AJAX function somewhere before AJAX.send
//
AJAX.setRequestHeader("ajax-token", "<?php echo $_SESSION["token"]; ?>");
//
// That creates $_SERVER['HTTP_AJAX_TOKEN'] which we can use later
ajax_responder.php
session_start(); // Must have
if ($_SERVER['HTTP_AJAX_TOKEN'] === $_SESSION["token"]) {
$token_match = true;
} else {
echo "No script kiddies!";
exit();
}
// Now it's safe for your AJAX responder to proceed
Let's put all of this into a working example
sending_from.php
<?php
session_start();
$token = bin2hex(random_bytes(64));
$_SESSION["token"] = $token;
?>
<!DOCTYPE html>
<html>
<head>
<title>My AJAX Sender</title>
</head>
<body>
<script>
function ajaxFormData(formID, postTo, ajaxUpdate) {
// Bind a new event listener every time the <form> is changed:
const FORM = document.getElementById(formID); // <form> by ID
const FD = new FormData(FORM); // Bind to-send data to form element
const AJAX = new XMLHttpRequest(); // AJAX handler
// This runs when AJAX responds
AJAX.addEventListener( "load", function(event) {
document.getElementById(ajaxUpdate).innerHTML = event.target.responseText;
} );
// This runs if AJAX fails
AJAX.addEventListener( "error", function(event) {
document.getElementById(ajaxUpdate).innerHTML = 'Oops! Something went wrong.';
} );
// Add your token header
AJAX.setRequestHeader("ajax-token", "<?php echo $_SESSION["token"]; ?>");
// Open the POST connection
AJAX.open("POST", postTo);
// Data sent is from the form
AJAX.send(FD);
}
</script>
<div id="ajax_changes">Replace me with AJAX</div>
<form id="ajaxForm">
<input type="text" name="the_simple_response">
<button type="button" onclick="ajaxFormData('ajaxForm', 'ajax_responder.php', 'ajax_changes');">Send my Secure AJAX</button>
</form>
</body>
</html>
ajaxcheck.inc.php
<?php
$mysite = 'https://example.tld';
// All in one test
if (($_SERVER['REQUEST_METHOD'] == 'POST')
&& ((!empty($_SERVER['HTTP_REFERER'])) && ($_SERVER['HTTP_REFERER'] === "$mysite/my_sending_page.php"))
&& ((!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) && ( strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'))
&& ($_SERVER['HTTP_AJAX_TOKEN'] === $_SESSION["token"])) {
$ajax_legit = true;
} else {
echo "No script kiddies!";
exit();
}
?>
ajax_responder.php
<?php
session_start();
// Do all that checking we're learning about by neatly including the file above
require_once('ajaxcheck.inc.php');
// Process your AJAX
echo $_POST['the_simple_response'];
?>
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data?
Nothing. This URL is public thus anyone can make requests to it.
how can i secure it and make sure only calls from my application will get the relevant data back?
You can pass additional data (for example, some hashed value) that is verified on the server side.
$http({
url : 'server/server.php',
method : 'GET',
data : { getContent : true, hash : '0800fc577294c34e0b28ad2839435945' }
});
and
if(isset($_GET['getContent']))
{
if(isset($_GET['hash']) && validateHash($_GET['hash']))
{
$content = get_content();
}
}
function get_content(){...}
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data?
The same way you would protect the data in any other request (e.g. with user authentication). There's nothing special about Ajax in regards to HTTP as far as the server is concerned.
how can i secure it and make sure only calls from my application will get the relevant data back?
You can't. The user can always inspect what their browser is asking the server for and replicate it.
Generally, people authenticate users rather than applications.

Request timeout

I'm using some jQuery to display tweets but once the Twitter API limit is reached, the request is sent but just keeps loading and loading. This doesn't look good. I want to be able to determine if the request is taking too long and then obviously do stuff, like cancel the request, change the styling, etc.
So this is the code that sends the request:
var fileref = document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", "http://search.twitter.com/search.json?q="+buildString+"&callback=TweetTick&rpp=50");
document.getElementsByTagName("head")[0].appendChild(fileref);
And this is the TweetTick function:
function TweetTick(ob)
{
var container=$('#tweet-container');
container.html('');
$(ob.results).each(function(el){
/* in here, a div is built for each tweet and then appended to container */
});
container.jScrollPane(); /* just adds the scrollbar */
}
You need to cache twitter api response on your server side.
How do I keep from running into the rate limit?
I had a very similar problem lately. I use this script by Remy Sharp for most of my twitter requests: http://remysharp.com/2007/05/18/add-twitter-to-your-blog-step-by-step/
What you need to realise is that the api timeout is per IP address. So if the api has timed out for you based on your testing, it won't have timed out for someone else on a different IP address. Now, if someone accessing the site is doing so within a corporation or business, and others in the same place are doing the same, that timeout will occur almost instantaneously.
To get around this you need to cache your results. The way I did this was as follows.
I created a twitter caching system using the following code:
$twitter_username = "tadywankenobi"; //
$number_of_tweets = "10";
$options[CURLOPT_URL] = 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name='.$twitter_username.'&count='.$number_of_tweets.'&include_rts=1';
$options[CURLOPT_PORT] = 80;
$options[CURLOPT_FOLLOWLOCATION] = true;
$options[CURLOPT_RETURNTRANSFER] = true;
$options[CURLOPT_TIMEOUT] = 60;
$tweets = cache($options);
$twxml = new SimpleXMLElement($tweets);
echo "<ul>";
for($i=0;$i<=($number_of_tweets-1);$i++){
$text = $twxml->status[$i]->text;
echo "<li>".auto_link_twitter($text)."</li>";
}
echo "</ul>";
function cache($options) {
$cache_filename = "/var/cache/tweets.xml";
if(!file_exists($cache_filename)){
$handle = fopen($cache_filename, 'w') or die('Cannot open file: '.$my_file);
fclose($handle);
}// Check if cache file exists and if not, create it
$time_expire = filectime($cache_filename) + 60*60; // Expire Time (1 hour) // Comment for first run
// Set time to check file against
if(filectime($cache_filename) >= $time_expire || filesize($cache_filename) == 0) {
// File is too old or empty, refresh cache
$curl = curl_init();
curl_setopt_array($curl, $options);
$response = curl_exec($curl);
curl_close($curl);
if($response){
file_put_contents($cache_filename, $response);
}
else{
unlink($cache_filename);
}
}else{
$response = file_get_contents($cache_filename);
}
return $response;
}
What the cache function at the end does is create a file on the server and stores the twitter xml feedback in there. The system then checks to see the age of that file and if it's younger than an hour old, it takes its results from there. Otherwise, it re-accesses twitter. You need to have the file writable in the /var/cache folder (create it if it's not there).
I've kinda hacked this code together a bit, so let me know if you run into any issues with it. It also uses an auto_link_twitter() function, which creates the links required within the twitter text. I didn't write that, so I'll try and find you a link to it now.
Hope that all helps,
T
UPDATE: I can't remember where I got the auto_link_twitter() function, so here it is. If the person who wrote it reads this post, my apologies, I couldn't find the source again.
function auto_link_twitter($text) {
// properly formatted URLs
$urls = "/(((http[s]?:\/\/)|(www\.))?(([a-z][-a-z0-9]+\.)?[a-z][-a-z0-9]+\.[a-z]+(\.[a-z]{2,2})?)\/?[a-z0-9._\/~#&=;%+?-]+[a-z0-9\/#=?]{1,1})/is";
$text = preg_replace($urls, " <a href='$1'>$1</a>", $text);
// URLs without protocols
$text = preg_replace("/href=\"www/", "href=\"http://www", $text);
// Twitter usernames
$twitter = "/#([A-Za-z0-9_]+)/is";
$text = preg_replace ($twitter, " <a href='http://twitter.com/$1'>#$1</a>", $text);
// Twitter hashtags
$hashtag = "/#([A-Aa-z0-9_-]+)/is";
$text = preg_replace ($hashtag, " <a href='http://twitter.com/#!/search?q=%23$1'>#$1</a>", $text);
return $text;
}
You can use specific jQuery methods to make a JSONP request. There is basic $.ajax method and shorthand method $.getJSON which fits better for you. To control timeout of the request you can use timeout parameter. Request exceeded timeout can be processed using the error callback.
$.ajax(
dataType: 'jsonp',
url: 'http://search.twitter.com/search.json',
data: {
q: buildString,
rpp: 50
},
jsonpCallback: 'TweetTick',
timeout: 30000,
error: function(jqXHR, textStatus, errorThrown) {
if (textStatus == 'timeout') {
alert('timeout exceeded');
}
}
);

validating a webpage with javascript

I need to find out if a page is returning a 404 or 301 status code. I know I can write a php script to use cURL to return a value for javascript to read, but I am trying to simplify the process and kinda new. Right now I have an onBlur function that makes sure the webpage is at least in the correct format before they leave the field. But I would like it to also check the status of the page and I can't seem to find a solution for using cUrl directly with javascript or any examples of how this would be done. Anybody care to help me out please? Here is my validate.js that I am calling on the page...
function loadXMLDoc() {
var url = document.getElementById("webpage_url").value;
var xmlhttp;
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("valid").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "custom/modules/CT221_SEP_test/js/curltest.php/" + url, true);
xmlhttp.send();
}
function isURL() {
var url = document.getElementById("webpage_url");
var urlerr = document.getElementById("url_error");
var reg = /http:\/\/[A-Za-z0-9\.-]{3,}\.[A-Za-z]{3}/;
if (!reg.test(url.value)) {
urlerr.innerHTML = "Invalid WebPage Address";
url.focus();
} else {
loadXMLDoc();
urlerr.innerHTML = //calls success image";
}
}
YAHOO.util.Event.on("webpage_url", "blur", isURL);
then my curltest.php file looks like this...
$url = $_GET['url'];
function validateurl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);
preg_match("/HTTP\/1\.[1|0]\s(\d{3})/", $data, $matches);
return $matches[1];
}
$code = validateurl($url);
if ($code != "404") {
echo "Webpage is valid";
} else[
echo "Webpage is not live";
}
Sounds like a simple case of creating a PHP proxy script. The function that validates the URL could (on success) call an AJAX function to a PHP scrip, passing the URL so that you can make a cURL request to it. Instead of pinging the website directly, you could opt use some sort of DNS lookup. Upon your PHP script finishing, you can return some sort of value/data to the AJAX function which can act accordingly on the page. Chances are you will need to use callbacks on the client and server side so as not to hang the page, unless that is preferable to them moving on with the rest of the form. Your call.

Categories