I have a Perl script which will allow for a file to be uploaded to my server. I'm not completely done with it yet, but I would like to know, if there is any way for me to get the full path of a file i uploaded. Shouldn't this be possible by checking the PATH_INFO environment variable, but when i try to check the path info, nothing is there
#!/usr/bin/perl
use strict;
use CGI;
use File::Basename;
#Virtual Directory
eval
{
my ($uploadfile, $cgi);
$cgi = new CGI;
$uploadfile = $cgi->upload('uploadfile');
print $uploadfile;
use constant PASSWORD => 'p3rlD3v3l0p3r';
use constant UPLOAD_DIR => '/home/user/files';
print <<"HTML";
Status: 200 OK
Content-Type: text/html
<html>
<head>
<title>Virtual Directory</title>
</head>
<body>
$uploadfile
<h2>Upload a new file</h2>
<form method = "POST" enctype = "multipart/form-data" action =""/>
File:<input type = "file" name="uploadfile"/>
<p>Password:
<input type = "password" name ="passwd"/></p>
<p><input type = "submit" value= "Submit File" /></p>
</form>
</body>
</html>
HTML
print $ENV{"PATH_INFO"};
};
It is hard to make sense of your question. However, do read Processing a File Upload Field in CGI docs. I think you might be looking for:
Accessing the temp files directly
When processing an uploaded file, CGI.pm creates a temporary file on your hard disk and passes you a file handle to that file. After you are finished with the file handle, CGI.pm unlinks (deletes) the temporary file. If you need to you can access the temporary file directly. You can access the temp file for a file upload by passing the file name to the tmpFileName() method:
On the other hand, if you are trying to find out the full path of the file on the web site visitor's computer, I hope it should be obvious that there is no way for your script to retrieve this information if it is not submitted by the user's browser as the name of the file:
If you want the entered file name for the file, you can just call param():
$filename = $q->param('field_name');
Different browsers will return slightly different things for the name. Some browsers return the filename only. Others return the full path to the file, using the path conventions of the user's machine. Regardless, the name returned is always the name of the file on the user's machine, and is unrelated to the name of the temporary file that CGI.pm creates during upload spooling
PATH_INFO is for other purposes. You need "tmpFileName":
my $cgi = CGI->new;
my $filename = $cgi->param('uploadfile');
my $tmpfilename = $cgi->tmpFileName($filename);
You can extract path with "fileparse" from File::Basename.
Related
I'm learning fatfree's route and found it behaves unexpected.
Here is my code in index.php:
$f3 = require_once(dirname(dirname(__FILE__)). '/lib/base.php');
$f3 = \Base::instance();
echo 'received uri: '.$_SERVER['REQUEST_URI'].'<br>';
$f3->route('GET /brew/#count',
function($f3,$params) {
echo $params['count'].' bottles of beer on the wall.';
}
);
$f3->run();
and here is the URL which I access: http://xx.xx.xx.xx:8090/brew/12
I get a 404 error:
received uri: /brew/12
Not Found
HTTP 404 (GET /12)
the strange thing is that the URI in F3 is now "/12" instead of "/brew/12" and I guess this is the issue.
When I check the base.php (3.6.5), $this->hive['BASE'] = "/brew" and $this->hive['PATH'] = "/12".
But if F3 only uses $this->hive['PATH'] to match the predefined route, it won't be able to match them.
If I change the route to:
$f3->route('GET /brew',
and use the URL: http://xx.xx.xx.xx:8090/brew, then the route matches without issue.
In this case, $this->hive['BASE'] = "" and $this->hive['PATH'] = "/brew". If F3 compares the $this->hive['PATH'] with predefined route, they match each other.
BTW, I'm using PHP's built-in web server and since $_SERVER['REQUEST_URI'] (which is used by base.php) returns the correct URI, I don't think there is anything wrong with the URL rewrite in my .htrouter.php.
Any idea? What did I miss here?
add the content of .htrouter.php here
<?php
#get the relative URL
$uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
#if request to a real file (such as a html, image, js, css) then leave it as it is
if ($uri !== '/' && file_exists(__DIR__ . $uri)) {
return false;
}
#if request virtual URL then pass it to the bootstrap file - index.php
$_GET['_url'] = $_SERVER['REQUEST_URI'];
require_once __DIR__ . './public/index.php';
Your issue is directly related to the way you're using the PHP built-in web server.
As stated in the PHP docs, here's how the server handles requests:
URI requests are served from the current working directory where PHP was started, unless the -t option is used to specify an explicit document root. If a URI request does not specify a file, then either index.php or index.html in the given directory are returned. If neither file exists, the lookup for index.php and index.html will be continued in the parent directory and so on until one is found or the document root has been reached. If an index.php or index.html is found, it is returned and $_SERVER['PATH_INFO'] is set to the trailing part of the URI. Otherwise a 404 response code is returned.
If a PHP file is given on the command line when the web server is started it is treated as a "router" script. The script is run at the start of each HTTP request. If this script returns FALSE, then the requested resource is returned as-is. Otherwise the script's output is returned to the browser.
That means that, by default (without a router script), the web server is doing a pretty good job for routing unexisting URIs to your document root index.php file.
In other words, provided your file structure is like:
lib/
base.php
template.php
etc.
public/
index.php
The following command is enough to start your server and dispatch the requests properly to the framework:
php -S 0.0.0.0:8090 -t public/
Or if you're running the command directly from the public/ folder:
cd public
php -S 0.0.0.0:8090
Beware that the working directory of your application depends on the folder from which you call the command. In order to leverage this value, I strongly advise you to add chdir(__DIR__); at the top of your public/index.php file. This way, all subsequent require calls will be relative to your public/ folder. For ex: $f3 = require('../lib/base.php');
Routing file-style URIs
The built-in server, by default, won't pass unexisting file URIs to your index.php, as stated in:
If a URI request does not specify a file, then either index.php or index.html in the given directory are returned
So if you plan to define some routes with dots, such as:
$f3->route('GET /brew.json','Brew->json');
$f3->route('GET /brew.html','Brew->html');
Then it won't work because PHP won't pass the request to index.php.
In that case, you need to call a custom router, such as the .htrouter.php you were trying to use. The only thing is that your .htrouter.php has obviously been designed for a different framework (F3 doesn't care about $_GET['url'] but cares about $_SERVER['SCRIPT_NAME'].
Here's an exemple of .htrouter.php that should work with F3:
// public directory definition
$public_dir=__DIR__.'/public';
// serve existing files as-is
if (file_exists($public_dir.$_SERVER['REQUEST_URI']))
return FALSE;
// patch SCRIPT_NAME and pass the request to index.php
$_SERVER['SCRIPT_NAME']='index.php';
require($public_dir.'/index.php');
NB: the $public_dir variable should be set accordingly to the location of the .htrouter.php file.
For example if you call:
php -S 0.0.0.0:8090 -t public/ .htrouter.php
it should be $public_dir=__DIR__.'/public'.
But if you call:
cd public
php -S 0.0.0.0:8090 .htrouter.php
it should be $public_dir=__DIR__.
OK, I checked the base.php and found out when f3 calculates the base URI, it uses $_SERVER['SCRIPT_NAME'].
$base='';
if (!$cli)
$base=rtrim($this->fixslashes(
dirname($_SERVER['SCRIPT_NAME'])),'/');
if we have web server directly forward all requests to index.php, then
_SERVER['SCRIPT_NAME'] = /index.php, and in this this case, base is ''.
if we use URL rewriting via .htrouter.php to index.php, then
_SERVER['SCRIPT_NAME'] = /brew/12, and in this this case, base is '/brew' which causes the issue.
Since I'm going to use the URL rewrite, I have to comment out the if statement and make sure base =''.
Thanks xfra35 for providing the clue.
Apache like php router here:
It can url rewrite.
https://github.com/kyesil/QPHP/blob/master/router.php
Usage:
php -S localhost:8081 router.php
Use case - I have an embedded box that has two files
One big file containing debug logs , user logs to assist in technical field issues. This big file is basically a zip file around 100 Mb.
Another file - small file containing configuration - around 3 Kb.
My requirement is to post these files to a webServer.
Technology - In order to post this file, I am using libcurl.
My assumptions about Web Server - This might be a form containing file input type.
<form method="post" enctype="multipart/form-data">
<div>
<label for="file">Choose file to upload</label>
<input type="file" id="file" name="Myfile" multiple>
</div>
<div>
<button>Submit</button>
</div>
</form>
Also, it might be running node server to handle the POST request.
Question
1) Is curl -F a best option here to post such files rather than curl -d or -d binary option?
2) Generally, do we have seperate forms for each file type for example technical field file and another form for configuration file?
if not, then is it a good idea to ask user to enter the input file tag name so that curl -F option can work accurately irrespective how a Webserver is setup?
Basically, according to the example - myFile can be any name so is it a good idea to ask user to pass this name? What is the short or popular name for file tag name - Myfile? So that I can ask user to enter this information.
Realized that HTTP/HTTPS PUT method is the appropriate solution here.
This way there is no need for form or formidable npm module.
Here is the curl page for PUT - How to do a PUT request with curl?
var ciphers = [
'AES128-SHA',
'AES256-SHA'
].join(':');
var options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem'),
ciphers: ciphers
};
https.createServer(options, function(req, res)
{
if (req.method === 'PUT')
{
// use file npm module to copy the file content here.
// like fs.write
req.on('data', function(data)
{
// write data here ..
}
}
});
Client Side -
Here is the command line to test it -
curl -k -X PUT -F "myfile=#/test/Test.png" https://192.162.1.19/
Here is the libcurl code to test it .
https://curl.haxx.se/libcurl/c/httpput.html
Remember to link using
-lcurl
#gcc putCode.c -o putcode -lcurl
#./putCode /test/Music/joy.mp3 joyful.mp3
My idea is to save the images which the user uploads outside the context path as follow:
D:\somefolder\myWeb\web-app\
D:\somefolder\imagesOutsideContextPath\
The code for that is the next (working locally):
String path = servletContext.getRealPath("/");
String parentFolder = new File(path).getParentFile().getParent();
String imagesFolder = parentFolder + "\\imagesOutsideContextPath";
Another idea (if this one doesn't work on server) would be to save the images in the current user's home folder as #HoàngLong suggested me.
But I'm not able to load the images from the view. I think this article from official documentation is not valid for that purpose. The next code desn't load anything:
<img src="D:\\somefolder\\imagesOutsideContextPath\\bestImageEver.jpg" alt="if I don't see this message, I'll be happier">
How could I use the real path instead the an url path to load these images?
There's a new plugin that makes this easy, check out http://grails.org/plugin/img-indirect
Create an action
def profileImage() {
String profilePicturePath = "${grailsApplication.config.profilePictureDirectoryPath}/${params.id}"
File file = new File(profilePicturePath)
response.contentType = URLConnection.guessContentTypeFromName(file.getName())
response.outputStream << file.bytes
response.outputStream.flush()
}
and then call this action with image name in params like:
<g:img uri="${grailsApplication.config.grails.serverURL}/controller/profileImage/${user?.profilePicture?.fileName}"/>
I have declared the image directory file in my config.groovy file like:
profilePictureDirectoryPath = '/opt/CvSurgeon/profileImages'
You can set the src to an action. With that your user will not know where your images are stored (security) and you can easily change your logic to display them.
In the action, just get your image and print the bytes. Example here.
Firstly, thank you for your reference.
It's insecure to load images using real path. The web browser should know nothing about how the pictures are saved on server, therefore not aware of the folder structure.
What I mean is that the system should use a specific URL for all your pictures, such as http://your_app/photo/user/{id}. Then to that URL, you can construct an action which gets id as a parameter, look up the photo in your file system(of course you must store the picture folder in configuration), and render the photo back.
I try to import a local .json-file using d3.json().
The file filename.json is stored in the same folder as my html file.
Yet the (json)-parameter is null.
d3.json("filename.json", function(json) {
root = json;
root.x0 = h / 2;
root.y0 = 0;});
. . .
}
My code is basically the same as in this d3.js example
If you're running in a browser, you cannot load local files.
But it's fairly easy to run a dev server, on the commandline, simply cd into the directory with your files, then:
python -m SimpleHTTPServer
(or python -m http.server using python 3)
Now in your browser, go to localhost:3000 (or :8000 or whatever is shown on the commandline).
The following used to work in older versions of d3:
var json = {"my": "json"};
d3.json(json, function(json) {
root = json;
root.x0 = h / 2;
root.y0 = 0;
});
In version d3.v5, you should do it as
d3.json("file.json").then(function(data){ console.log(data)});
Similarly, with csv and other file formats.
You can find more details at https://github.com/d3/d3/blob/master/CHANGES.md
Adding to the previous answers it's simpler to use an HTTP server provided by most Linux/ Mac machines (just by having python installed).
Run the following command in the root of your project
python -m SimpleHTTPServer
Then instead of accessing file://.....index.html open your browser on http://localhost:8080 or the port provided by running the server. This way will make the browser fetch all the files in your project without being blocked.
http://bl.ocks.org/eyaler/10586116
Refer to this code, this is reading from a file and creating a graph.
I also had the same problem, but later I figured out that the problem was in the json file I was using(an extra comma). If you are getting null here try printing the error you are getting, like this may be.
d3.json("filename.json", function(error, graph) {
alert(error)
})
This is working in firefox, in chrome somehow its not printing the error.
Loading a local csv or json file with (d3)js is not safe to do. They prevent you from doing it. There are some solutions to get it working though. The following line basically does not work (csv or json) because it is a local import:
d3.csv("path_to_your_csv", function(data) {console.log(data) });
Solution 1:
Disable the security in your browser
Different browsers have different security setting that you can disable. This solution can work and you can load your files. Disabling is however not advisable. It will make you vulnerable for all kind of threads. On the other hand, who is going to use your software if you tell them to manually disable the security?
Disable the security in Chrome:
--disable-web-security
--allow-file-access-from-files
Solution 2:
Load your csv/json file from a website.
This may seem like a weird solution but it will work. It is an easy fix but can be unpractical though. See here for an example. Check out the page-source. This is the idea:
d3.csv("https://path_to_your_csv", function(data) {console.log(data) });
Solution 3:
Start you own browser, with e.g. Python.
Such a browser does not include all kind of security checks. This may be a solution when you experiment with your code on your own machine. In many cases, this may not be the solution when you have users. This example will serve HTTP on port 8888 unless it is already taken:
python -m http.server 8888
python -m SimpleHTTPServer 8888 &
Open the (Chrome) browser address bar and type the underneath. This will open the index.html. In case you have a different name, type the path to that local HTML page.
localhost:8888
Solution 4:
Use local-host and CORS
You may can use local-host and CORS but the approach is not user-friendly coz setting up this, may not be so straightforward.
Solution 5:
Embed your data in the HTML file
I like this solution the most. Instead of loading your csv, you can write a script that embeds your data directly in the html. This will allow users use their favorite browser, and there are no security issues. This solution may not be so elegant because your html file can grow very hard depending on your data but it will work though. See here for an example. Check out the page-source.
Remove this line:
d3.csv("path_to_your_csv", function(data) { })
Replace with this:
var data =
[
$DATA_COMES_HERE$
]
You can't readily read local files, at least not in Chrome, and possibly not in other browsers either.
The simplest workaround is to simply include your JSON data in your script file and then simply get rid of your d3.json call and keep the code in the callback you pass to it.
Your code would then look like this:
json = { ... };
root = json;
root.x0 = h / 2;
root.y0 = 0;
...
I have used this
d3.json("graph.json", function(error, xyz) {
if (error) throw error;
// the rest of my d3 graph code here
}
so you can refer to your json file by using the variable xyz and graph is the name of my local json file
Use resource as local variable
var filename = {x0:0,y0:0};
//you can change different name for the function than json
d3.json = (x,cb)=>cb.call(null,x);
d3.json(filename, function(json) {
root = json;
root.x0 = h / 2;
root.y0 = 0;});
//...
}
After turning on Google Drive API access from the management console and getting my Client ID keys, I followed the sample code (using Python 2.7) and I am able to insert a folder, set the appropriate permissions (type=anyone,role=reader), and insert a text/html type file into the new folder.
However the JSON file resource objects I receive from executing insert on the drive service have no 'webViewLink' field! There are 'webContentLink' and 'selfLink' fields but 'webViewLink', which is necessary for static HTML publishing, seems to be missing.
Most perplexing. If this feature hasn't been turned on yet or if I need to configure my account settings to allow HTML publishing please let me know. Any other help would be most appreciated ;)
The webViewLink property is only returned for public folders, and not the single files inside such folders. You can use that as the base url to construct links to your files.
The WebViewLink file property can be retrieved by doing something like this:
$file = $service->files->get($file_id, array('fields' => 'webViewLink'));
$web_link_view = $file->getWebViewLink();
OR
$sheetsList = $drive_service->files->listFiles([
'fields' => 'files(id, name, webViewLink, webContentLink)',
]);
$web_link_view = $sheetsList->current()->getWebViewLink();
Pay attention that you should load the file specifying which fields you wanna bring with it (In this case, webViewLink). If you don't do that, only id and name will be available.
If you also need to configure file permissions, you can do something like:
$permissions = new \Google_Service_Drive_Permission();
$permissions->setRole('writer');
$permissions->setType('anyone');
$drive_service->permissions->create($file_id, $permissions);
Possible values for setRole() and setType() can be found here: https://developers.google.com/drive/api/v3/reference/permissions/create