List Files on a server via front-end javascript - javascript

A have a folder filled with files accessible to the end user, and am working on a javascript file to parse through them and deliver them as needed. However, rather than manually updating the list, I'd like the javascript to scan the folder and then list iterate through an array of the files in that folder. Is there a decent way in front-end JS to do this? All solutions I've looked into have turned out to be purely for Node.
For example, say I have a folder structure like so...
/ (Web Root)
|__ /Build_a_card
|__ /Cool pictures
|__ /Summer Pictures
summer_dog.gif
smiling_sun.svg
|__ /Winter Pictures
snowman.png
cat.jpg
And then in the javascript I'd run something like
var image_list = get_list("/Cool Pictures");
build_select_list(image_list);
function get_list(folder_to_look_in){
var the_list = ???
return the_list;
}
...
And then, for example, the JS is run, and after some parsing, the user would see...
<select>
<option value="summer_pictures/summer_dog.gif">summer_dog.gif</option>
<option value="summer_pictures/smiling_sun.svg">smiling_sun.svg</option>
<option value="winter_pictures/snowman.png">snowman.png</option>
<option value="cat.jpg">cat.jpg</option>
</select>
In an insane world, since the individual files in the folder are accessible to javascript, hypothetically I could brute-force every single possible file name in the folder and return success on each one:
function get_list(folder){
var list_of_files = {};
var starting_character = 0;
list_of_files = every_single_option({starting_character}, 0, 40, folder)
}
}
function every_single_option(existing_characters, current_depth, max_depth, folder){
this_string = String.fromCharCode(existing_characters);
if (request_url(this_string, folder)){
there_array[this_string] = this_string;
}
var there_array = {}
var i;
if (current_depth < max_depth){
while (i < 127){
let temp_array = there_array;
temp_array[i] = i;
mix_source(there_array, every_single_option(existing_characters, current_depth + 1, max_depth, folder))
}
}
return there_array;
}
function request_url(url, folder){
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "/" + folder + "/" + url);
oReq.send();
}
function mix(source, target) {
for(var key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
}
but as mentioned, doing it that way would be insane (both ridiculously slow and very bad code design, resorting to brute-forcing your own website is just dumb.)
but it does hypothetically prove that there's no reason javascript shouldn't be able to just get a directory listing assuming public permissions. Alternatively, I could make some API with the backend that allows fetching a JSON that lists it, but that's requiring backend code for something that's a frontend process. I'm trying to pull this off with something sane and simple, but the question is... how?
(If you insist on posting a jquery way to do this, please also post a non-jquery way as well as there is no jquery available in my environment.)

So, refusing to admit it's impossible, I engineered a solution that works, and requires no API.
That said, the server has to not be actively blocking the javascript from viewing the directory. In other words, the server hasn't turned indexing off, and the directory doesn't have an index.html or equivalent to rewrite any attempt to index, and the server isn't doing some url-rewriting. In other words, this should work in any server environment that doesn't rewrite or block indexes.
Here's a rough draft (still buggy, needs finished):
var request = new XMLHttpRequest();
request.open('GET', '/my/directory/', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
}
};
request.send();
var directory_listing = resp;
var regexp = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i;
var match, files = [];
while ((match = regexp.exec(resp)) != null) {
files.push(match.index);
}
console.log(files);

Building off lilHar's answer, we can use DOMParser to create a shadow-DOM for the directory page we're accessing, and then use that to find any links we need:
// relative path to the desired directory
const directory = "/DIRECTORY-NAME/";
// selector for the relevant links in the directory's index page
const selector = "LINK SELECTOR";
const request = new XMLHttpRequest();
request.open("GET", directory, true);
request.onload = () => {
// succesful response
if(request.status >= 200 && request.status < 400)
{
// create DOM from response HTML
const doc = new DOMParser().parseFromString(request.responseText, "text/html");
// get all links
const links = doc.querySelectorAll(selector);
console.log("Links:", links);
links.forEach(link => {
// do stuff with the links
});
}
};
request.send();

Is there a decent way in front-end JS to do this?
No. Nor is that a way that isn't decent.
The front end can communicate with the server via HTTP or WebSockets.
Neither of those provides any built-in mechanism for exploring a filesystem.
You need the server to provide an API (e.g. a web service) which provides the information you want.

Related

Loading a .txt File into a JavaScript Variable without Selecting

I've asked this question before but did not explain it well enough so here's a better attempt:
I am making an application that will be run client-side, not server side. I have a .txt file in the directory with all of the code for the application, and I want to be able to automatically load the contents into a variable without the user needing to select anything. Thus, I do not want to use an input, but rather just have the file load itself when the .html page is opened. As an end result, I would want a String that contains the text inside the file.
I am not using any frameworks, just strictly coding in JavaScript, CSS, and HTML.
I assume that the answer to this question involves a Blob and using readAsText(), but even after reading the full documentation I'm unsure how to pass a URL into it so it can read the contents of a .txt file.
The easiest way of doing so is a XML request. This allows you to access the contents of files either asynchronously or synchronously. Please not that CORS will sometimes block this, so you may need to disable it if you are using chrome.
function getData(file) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
xmlhttp.open("GET", file, false);
//The false above means synchronously, true means asynchronously
xmlhttp.send();
return xmlhttp.responseText;
}
let myVar = getData("text.txt");
EDIT:
This code from Cors-anywhere at the beginning of the fuction can fix the cors policy
https://github.com/Rob--W/cors-anywhere/#documentation
(function() {
var cors_api_host = 'cors-anywhere.herokuapp.com';
var cors_api_url = 'https://' + cors_api_host + '/';
var slice = [].slice;
var origin = window.location.protocol + '//' + window.location.host;
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
var args = slice.call(arguments);
var targetOrigin = /^https?:\/\/([^\/]+)/i.exec(args[1]);
if (targetOrigin && targetOrigin[0].toLowerCase() !== origin &&
targetOrigin[1] !== cors_api_host) {
args[1] = cors_api_url + args[1];
}
return open.apply(this, args);
};
})();

capture file into javascript variable instead of downloading it

I am writing a app that visits a web site that can give me a link to a file, like this: http://www.thrustcurve.org/download.jsp?id=2199
If I visit this link, a small text file is downloaded. What I would like to do instead is to capture this text into a javascript variable so I can search around in it and extract the data I need.
Is this even possible?
Further details: although I am old and have lots of programming experience, I am a total noob in the javascript/web/server/modern space (think FORTRAN 77).
I now teach high school physics and am trying to build a web-based rocket simulator for my students to use on their chromebooks. The creator of thrustcurve.org has generously made data about rocket motors available on the web, but I need some bits that can only be found inside these little text files. Maybe it would be possible to work with the downloaded files on the chrome books, but I really have no idea how to begin there. If you are patient enough to have read this far, you can see the kind of javascript I have been able to accomplish at noragulfa.com
You can use XMLHttpRequest to perform HTTP requests, but due to security restrictions the browser blocks requests to “external domains” (thus, you can download files only from your domain). For more info, read about Cross-Origin Resource Sharing (CORS).
To solve your task, you have several options:
1) Download required files from thrustcurve.org and store them on your server. This is the best option since you will not be dependent on an external server (besides, hotlinking may upset the thrustcurve.org owner). In this case XMLHttpRequest will be able to access files using relative URLs:
var url = '/thrustcurve-downloads/Estes_A8.eng';
2) Contact the thrustcurve.org owner and ask him to enable Access-Control-Allow-Origin from anywhere. In this case XMLHttpRequest will be able to access files using full URLs:
var url = 'http://www.thrustcurve.org/download.jsp?id=2199';
3) Create a proxy that passes HTTP requests to thrustcurve.org. For example, since you are using nginx, you can simple add the following to your configuration file:
location /thrustcurve {
proxy_pass http://www.thrustcurve.org/;
}
In this case XMLHttpRequest will be able to access files using relative URLs:
var url = '/thrustcurve/download.jsp?id=2199';
4) Use third-party proxies (not a very reliable solution, but great for tests). As an example, I will use this option.
var url = 'http://cors-anywhere.herokuapp.com/http://www.thrustcurve.org/download.jsp?id=2199';
var xhr = new XMLHttpRequest();
xhr.onload = function () {
console.log(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'text';
xhr.send();
UPD: A full example how to download files using a XMLHttpRequest and PHP.
1) Create the file thrustcurve.php on your root server with the following contents:
<?php
// Change this to FALSE if don't want to store files locally
$store_files_locally = true;
$id = (int) filter_input(INPUT_GET, 'id');
if ($id > 0) {
if ($store_files_locally) {
// Specify the directory where you want to store engine files
// It will create the directory if it doesn't exist
$dir = __DIR__ . '/thrustcurve-downloads';
if (!is_dir($dir) && !mkdir($dir, true, 0777)) {
http_response_code(500);
die('Cannot create the downloads directory');
}
// If file exists, load the engine from the local file
$file = "{$dir}/{$id}.eng";
if (is_file($file)) {
$engine = file_get_contents($file);
die($engine);
}
}
// Download the engine file from the remote server
$url = "http://www.thrustcurve.org/download.jsp?id={$id}";
$engine = trim(#file_get_contents($url));
// The downloaded file is considered valid engine only if it starts with semicolon
if (strpos($engine, ';') === 0) {
if ($store_files_locally) {
file_put_contents($file, $engine);
}
die($engine);
}
}
http_response_code(404);
echo "File #{$id} not found";
2) To download files using JavaScript, use the following:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 200) {
console.log(xhr.response);
} else {
console.error(xhr.response);
}
};
xhr.open('GET', '/thrustcurve.php?id=2198');
xhr.responseType = 'text';
xhr.send();

By-pass virus scan for Google Drive links and get the confirm ID

With some help from this thread I came up with the code below. How can I fetch the Google Drive file ID, open the direct link to the file and snatch the virus scan confirm ID that is required to stream files over 100 MB and then puzzle back the link? I'm kind of stuck at the xhr part.
function fixGoogleDriveURL(url) {
if (url.indexOf('drive.google.com') !== -1) {
var DocIDfull = url;
var DocIDstart = DocIDfull.indexOf('open?id=');
if (DocIDstart == -1) {
// invalid
return url;
}
var DocID = DocIDfull.slice(DocIDstart+8);
url = 'https://drive.google.com/uc?export=download&id=' + DocID;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200) {
var token = xhr.responseText.match("/confirm=([0-9A-Za-z]+)&/");
window.location.replace(url + '&confirm=' + token[1]);
// should I add url += '&confirm=' + token[1] here instead of window.location?
}
}
};
xhr.open("GET", url);
xhr.send();
}
return url;
}
console.log(fixGoogleDriveURL('https://drive.google.com/open?id=1C25uoL6nIqqNhex3wm8VwODsO2q2pXBt') + "\n<-- should output:\nhttps://drive.google.com/uc?export=download&id=1C25uoL6nIqqNhex3wm8VwODsO2q2pXBt&confirm=XXXXX");
Scraping GDrive using Client-Side JavaScript isn't explicitly allowed by Google and therefore your Ajax call/XHR fails.
The only way to get around that restriction is by using a proxy in the middle that will forward Google's Website code but add appropriate Access-Control Allow-Origin Headers.
You can either use your own server for that (some minimal server-side script code will do) or you can use a service like http://multiverso.me/AllOrigins/ or https://corsproxy.github.io/ to proxy the request for you.
The AllOrigins site has some example code for use with jQuery, but basically they work by URI encoding the URL you want to access and appending that string to the site's proxy URL.
Here's an article by freecodecamp.org that outlines how to use these services (skip to the Don’t Let CORS Stop You! section.
Note: A security advice: These services are working fine right now, but they could go out of business tomorrow and start serving malicious data instead or redirect your file requests to completely different files or completely different websites altogether. It's up to you to decide if you want to trust these strangers or not.

Finding files in a directory

I'm trying to find one file which is of JSON type in my directory using JavaScript. However, when I look at google results, they claim that JavaScript cannot do such a thing because it is a client-side language. However, when I do the following code (which isn't what I want, but it works), which specifies the file I am looking for, it works. I was wondering why this is the case. Is it because I am using jQuery?
To clarify, I have a directory containing my html file and JSON file, and the Scene.js file is in a subdirectory. So, it looks like:
-labvtk
---ch4_CameraTypes.html (the html file)
---noise.json
---js
-----webgl
-------Scene.js
If this is the case, how would you suggest I find one file which is of JSON type( like *.json perhaps) instead of saying explicitly the file name (noise.json in this one case)?
Javascript code:
var Scene = {
objects : [],
getObject : function(alias){
for(var i=0; i<Scene.objects.length; i++){
if (alias == Scene.objects[i].alias) return Scene.objects[i];
}
return null;
},
loadObject : function(filename) {
var request = new XMLHttpRequest();
console.info('Requesting ' + filename);
request.open("GET",filename);
request.onreadystatechange = function() {
if (request.readyState == 4) {
if(request.status == 404) {
console.info(filename + ' does not exist');
}
else {
var o = JSON.parse(request.responseText);
o.remote = true;
Scene.addObject(o);
}
}
}
request.send();
},
addObject : function(object) {
...
and html file (which has some javascript in it)
...
<script type='text/javascript' src='js/gui/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src='js/gui/jquery-ui-1.8.13.custom.min.js'></script>
<script type='text/javascript' src='js/webgl/Scene.js'></script>
...
function load(){
Scene.loadObject('noise.json');
}
...
This code was mostly taken from http://tinyurl.com/merdnch
The Google entries you have found are quite right: you can't search a server with Javascript. You can, as you have demonstrated, find a file if you already know the name.
The only way to search on the server is to implement a script on the server that does so. You might use PHP's scandir() or glob() functions, for example. There are many other ways.
This question might give you some pointers.

Creating an XML file using Javascript

I have the following code:
xmlDoc=loadXMLDoc("dbbackup.xml");
x=xmlDoc.getElementsByTagName("record");
alert(x);
for (i=0;i<3;i++) {
newel=xmlDoc.createElement("edition");
newtext=xmlDoc.createTextNode("first");
alert("x : "+x[i]);
alert("newtext :"+newtext.nodevalue);
x[i].appendChild(newel);
alert("sd");
}
function loadXMLDoc(dname) {
if (window.XMLHttpRequest) {
xhttp=new XMLHttpRequest();
} else {
xhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;
}
I have created dbbackup.xml in the same location and the XML file looks like:
<sticky>
<record></record>
</sticky>
But after running my script the xml file is not getting updated.
Javascript cannot modify files on disk, it only runs for the client in the client's web browser.
To actually write to and from files on a server, you have to use server-side languages and technologies, like PHP or ASP.
I made this - making XML at client side then using everyday praksis
Mike
function makeSlot() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) showBon(); }
xmlhttp.open("POST","crMakeSlot.php",true);
xmlhttp.send(wrapUp());
}
/***
* make the final transaction - using XML
*/
function wrapUp () {
var transaction = document.implementation.createDocument("","", null);
var operator = document.createElement("operator");
var textblok1 = document.createTextNode(document.getElementById("rText").value);
operator.appendChild(textblok1);
var root = document.createElement("transaction");
root.setAttribute("tstamp", now);
root.setAttribute("sequenceno", zSequenceNo.textContent);
if (parseInt(document.getElementById("zDankort").value) > 0) root.setAttribute("dankort", document.getElementById("zDankort").value);
if (parseInt(document.getElementById("zCash").value) > 0) root.setAttribute("cash", document.getElementById("zCash").value);
if (parseInt(document.getElementById("zCredit").value) > 0) root.setAttribute("credit", document.getElementById("zCredit").value);
if (parseInt(document.getElementById("zCheck").value) > 0) root.setAttribute("check", document.getElementById("zCheck").value);
if (parseInt(document.getElementById("zGiftcard").value) > 0) root.setAttribute("giftcard", document.getElementById("zGiftcard").value);
if (parseInt(document.getElementById("zVoucher").value) > 0) root.setAttribute("voucher", document.getElementById("zVoucher").value);
root.appendChild(operator);
var divObj = document.getElementsByTagName("div");
/***
* when column value is 4, then we have our data complete - next cycle
*/
for (ix = 0; ix < divObj.length; ix++) {
switch (divObj[ix].getAttribute("column")) {
case "1": var row = document.createElement("row"); row.setAttribute("item",divObj[ix].textContent);
case "2": row.setAttribute("price",divObj[ix].textContent);
case "3": row.setAttribute("quantum",divObj[ix].textContent);
case "4": root.appendChild(row);
default: break;
}
}
transaction.appendChild(root);
return(transaction);
}
SomeKidWithHTML is right.
JavaScript is designed to only modify a file, in memory, that is loaded inside a browser framework.
Think of the browser as a sandbox that your kids (html, xml, etc.) can play in. As long as Johnny (xml) is in the sandbox playing, all is well. But if Johnny were allowed to play outside of that sandbox, just think of the havoc that could be done on your machine by websites.
There is NO WAY a JavaScript can permanentally affect a file on your local machine, by itself. It can only play inside the sandbox (locally, it can make calls to Java, or an other API, to affect change, but that's a whole other deal).
JavaScript is client side only. If you expect it to affect a server, it can only do it through calls back to the server. At the server you will need some kind of programming (asp.net, java, php, html, others) to receive and answer that call and do something with it.
JavaScript, by itself, is very powerful... but only inisde the sandbox (browser). For it to affect anything else outside of that browser it must depend on other programs already in place and ready to receive those requests.
And this is all in the name of security, mostly.
You can collect data from the web page in client side and send them to the server (ajax), which will then generate the xml file and send back a link to the file (ajax). Use javascript to generate a download link using the link returned by the server.
This is the way I do to solve the problem in one of my project.

Categories

Resources