problems with symbols (scandir, array_diff, foreach) - php

I'm trying to write a script which open the directory, scan all files (images) and displayed it on the screen, but the problem is, it contains symbols in their names and scandir can't handle it.
It's ok with the directories where no symbols are present in their names, the script works perfect, but the directories/files with the symbols in their name is a big problem.
For instance, I have a total 2 directories and all files in that directories contains the same symbols in their name. One contain "®" and the other contain "™" and every single file (image) have these symbol in their names, for example: "Right® screen452217.jpg". So, renaming the directories and files is not an option, this would take too much time.
Maybe is there a better way, but I do it directly from url on screen with $_GET. It's on a local server for now, I'm working in VertrigoServ WAMP server and the script then look like:
http://127.0.0.1/screenshots/index.php?page=Rights®
http://127.0.0.1/screenshots/index.php?page=Trade%20Marks™
$url = "screens/".$_GET["page"]."";
$scan = scandir($url, SCANDIR_SORT_NONE);
$scaned = array_diff($scan, array('.', '..', 'Thumbs.db'));
foreach($scaned as $shots) {
if ($shots <> "thumbnails") {
echo "<li>".PHP_EOL.
" <img width=\"253\" height=\"158\" src=\"".$url."\\".$shots."\"".
" alt=\"".$shots."\" title=\"".$shots."\".
" </li>".PHP_EOL.PHP_EOL;
}
}
scandir reports these errors:
The system cannot find the file specified. (code: 2)
failed to open dir: No such file or directory
No such file or directory
array_diff reports this error:
Argument #1 is not an array
and finally foreach report:
Invalid argument supplied for foreach()
I also tried to change encoding with mb_convert_encoding() and iconv(), but no luck.
My best result was after changing url, instead of using "®" or "™" I used windows-1252 ASCII Encoding Reference:
http://127.0.0.1/screenshots/index.php?page=Rights%AE
http://127.0.0.1/screenshots/index.php?page=Trade%20Marks%99
Then everything passed with no error, but instead of showing images, the "img src" looks like:
screens/Rights�\Right�452217.jpg
which is still problem, because images are not displayed. I like to stick with scandir, because I already have done the page, but I can't pass through this problems with symbols. Can you help me, please ?

It was actually simpler than I thought. Problem was, that the directory was already with symbols in their names, so I must change that to Windows-1252 like this:
$page = $_GET["page"];
if (strpos($page, '®')) {$page = str_replace('®', '%AE', $page);}
if (strpos($page, '™')) {$page = str_replace('™', '%99', $page);}
Then the URLs change from:
http://127.0.0.1/screenshots/index.php?page=Rights®
http://127.0.0.1/screenshots/index.php?page=Trade%20Marks™
To:
http://127.0.0.1/screenshots/index.php?page=Rights%AE
http://127.0.0.1/screenshots/index.php?page=Trade%20Marks%99
Then it was simple, just add encoding after scandir and one in foreach:
$url = "screens/".$_GET["page"]."";
$scan = scandir($url, SCANDIR_SORT_NONE);
$scaned = array_diff($scan, array('.', '..', 'Thumbs.db'));
$url = iconv("windows-1252", "UTF-8", $screen_uplay);
foreach($scaned as $shots) {
if ($shots <> "thumbnails") {
$shots = iconv("windows-1252", "UTF-8", $shots);
echo "<li>".PHP_EOL.
" <img width=\"253\" height=\"158\" src=\"".$url."\\".$shots."\"".
" alt=\"".$shots."\" title=\"".$shots."\".
" </li>".PHP_EOL.PHP_EOL;
}
}
Simple as that. Maybe is there a better way, but this is working for me and I'm ok with that.

Related

Why file_get_contents not working in PHP?

This code get content file txt:
$str = "c:\\\\表\\t.txt";
$con=file_get_contents( $str);
echo $con;
File exist in folder:
Result: show error:
Warning: file_get_contents(c:\表\t.txt): failed to open stream: No such file or directory in C:\xampp\htdocs\direction\test.php on line 6
Why is file_get_contents() not working?
How read content of path c:\表\t.txt?
Try to use urlencode to encode your directory name:
$str = 'c:\\'.urlencode('表').'\t.txt';
$con=file_get_contents( $str);
echo $con;
This is described here in detail.
EDIT
Assuming you're using UTF-8 encoded source files, you could also try one of the following
$str = 'c:\\'.urlencode(mb_convert_encoding('表', 'UTF-16', 'UTF-8')).'\t.txt';
// or just
$str = 'c:\\'.mb_convert_encoding('表', 'UTF-16', 'UTF-8').'\t.txt';
As far as I know newer (> FAT32) Microsoft filesystems use UTF-16 encoding. But this will make your solution fail on other (e.g. Linux) filesystems.
EDIT 2
You can also try to convert your UTF-8 filename into a different encoding such as SJIS, SJIS-win, SJIS-2004, JIS, EUC-JP, eucJP-win, EUC-JP-2004, CP932, JIS-ms or the like. But I'm not an expert in east asian character encodings - so treat that information with caution.
try this
<?PHP
$con=file_get_contents('./表/t.txt', true);
$con=file_get_contents('./表/t.txt',FILE_USE_INCLUDE_PATH);
echo $con;
?>
Language : PHP
$results = scandir('c:\');
$result will give you all folder name inside c drive.
you can find your folder in $result array.
now you have folder name in $result and now you can go to file.
Modified :
$results = scandir('/web');
$results = "/web/$results[21]/t.txt";
$con=file_get_contents( $results);
echo $con;
Explanation :
1.) /web is the directory where is 表 folder and some other folders.
2.) $result[21] is giving me value 表 on browser i know its 表 folder.
3.) Now you have file path. Go ahead.
NOTE : If you still use Chinese character in your folder and file then you have to change your OS from window to ubuntu.
Create path based on single /
$content = file_get_contents("C:/表/t.txt");
You can read more about Filesystem here: http://php.net/manual/en/wrappers.file.php

PHP - Windows - filename incorrect after upload (ü saved as ü etc.) [duplicate]

This question already has answers here:
PHP - Upload utf-8 filename
(9 answers)
UTF-8 all the way through
(13 answers)
Closed 4 months ago.
I have this home made app that allows multiple file uploads, I pass the files to php with AJAX, create new dir with php, move there uploaded files and save the dir location to database. Then to see the files I run listing of the directory location saved in the db.
The problem is that files come from all around the world so very often they have some non latin characters like for example ü. When I echo the filename in php names appear correctly even when they have names written in Arabic, yet they are being saved on the server with encoded names as for example ü in place of ü. When I list the files from directory I can see the name ü.txt insted of ü.txt but when I click on it server returns error object not found (since on the server it is saved as ü.txt and it reads the link as ü.txt).
I tried some of the suggested solutions as for example using iconv, but the filenames are still being saved the same way.
I could swear the problem wasn't present when the web app was hosted on linux, but at the moment I am not so sure about it anymore. Right now I temporarily run it on xampp (on Windows) and it seems like filenames are saved using windows-1252 encoding (default Windows' encoding on the server). Is it default Windows encoding related problem?
To be honest I do not know how to approach that problem and I would appreciate any help. Should I keep on trying to save the files in different character encoding or would it be better to approach it different way and change the manner of listing the already saved and encoded files?
EDIT. According to the (finally) closed bug report it was fixed in php 7.1.
In the end I solved it with the following approach:
When uploading the files I urlencode the names with rawurlencode()
When fetching the files from server they are obviously URL encoded so I use urldecode($filename) to print correct names
Links in a href are automatically translated, so for example "%20" becomes a " " and URL ends up being incorrect since it links to incorrect filename. I decided to encode them back and print them ending up with something like this: print $dirReceived.rawurlencode($file); ($dirReceived is the directory where received files are stored, defined earlier in the code)
I also added download attribute with urldecode($filename) to save the file with UTF-8 name when needed.
Thanks to this I have files saved on the server with url encoded names. Can open them in browser (very important as most of them are *.pdf) and can download them with correct name which lets me upload and download even files with names written in Arabic, Cyrillic, etc.
So far I tested it and looks good. I am thinking of implementing it in production code. Any concerns/thoughts on it?
EDIT.
Since there are no objections I select my answer as the one that solved my problem. After doing some testing everything looks good on client and server side. When saving the files on server they are URL encoded, when downloading them they are decoded and saved with correct names.
At the beginning I was using the code:
for($i=0;$i<count($_FILES['file']['name']);$i++)
{
move_uploaded_file($_FILES['file']['tmp_name'][$i],
"../filepath/" . $_FILES['file']['name'][$i]);
}
This method caused the problem upon saving file and replaced every UTF-8 special character with cp1252 encoded one (ü saved as ü etc.), so I added one line and replaced that code with the following:
for($i=0;$i<count($_FILES['file']['name']);$i++)
{
$fname= rawurlencode($_FILES['file']['name'][$i]);
move_uploaded_file($_FILES['file']['tmp_name'][$i],
"../filepath/" . $fname);
}
This allows me to save any filename on server using URL encoding (% and two hexadecimals) which is compatible with both cp1252 and UTF-8.
To list the saved files I use filepaths I have saved in DB and list them for files. I was using the following code:
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
if(is_file($dir . $file)){
echo "<li><a href='".$dir.$file."' download='".$file ."'>".$file."</a></li><br />";
}
}
closedir($dh);
}
}
Since URL encoded filenames were decoded automatically I changed it to:
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
if(is_file($dir . $file)){
echo "<li><a href='";
print $dir.rawurlencode($file);
echo "' download='" . urldecode($file) ."'>".urldecode($file)."</a></li><br />";
}
}
closedir($dh);
}
}
I don't know if this is the best way to solve it but works perfectly, also I am aware that it is generally a good practice not to use php to generate html tags but at the moment I have some critical bugs that need addressing so first that and then I'll have to work on the appearance of the code itself.
EDIT2
Also the great thing is I do not have to change names of the already uploaded files which in my case is a big advantage.
Are you using $_FILES['upfile']['name'] to name the file? That could create your problem.
How about using GNU Recode?
$fileName = recode_string('latin1',$_FILES['upfile']['name']);
Syntax:
recode_string(string recode type,string $string)
Valid Character sets: http://www.faqs.org/rfcs/rfc1345.html
Somehow you must validate the characters in the uploaded file name.
You could also try sprintf. The formatted string characters can be unpredictable, but will probably work.
$fileName = pathinfo($_FILES['upfile']['name'], PATHINFO_FILENAME);
$fileName = sprintf('./uploads/%s',$fileName);
When you save the file name use
$fileName = mysqli_real_escape_string($fileName)

Php function to remove spaces from uploaded photo

I am using Jquery uploader to upload images to my website. It uses a file called uploadhandler.php to manipulate the files. Inside the uploadhandler.php is the following function which appears to make changes to how the filename is formatted etc.
The problem I am having is if I upload a file with spaces in the file name it doesn't appear to be removing the spaces in the file name. Does anyone know how I can edit it to add an extra command to remove any spaces in the file name, or point me in the right direction on how to do it ?.
protected function trim_file_name($name, $type, $index, $content_range) {
// Remove path information and dots around the filename, to prevent uploading
// into different directories or replacing hidden system files.
// Also remove control characters and spaces (\x00..\x20) around the filename:
$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
// Add missing file extension for known image types:
if (strpos($file_name, '.') === false &&
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
$file_name .= '.'.$matches[1];
}
while(is_dir($this->get_upload_path($file_name))) {
$file_name = $this->upcount_name($file_name);
}
$uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1]));
while(is_file($this->get_upload_path($file_name))) {
if ($uploaded_bytes === $this->get_file_size(
$this->get_upload_path($file_name))) {
break;
}
$file_name = $this->upcount_name($file_name);
}
return $file_name;
}
The line:
$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
Will remove spaces "around" the filename, such as "foo " because of the x20 bit which is a space. You could simply add directly after this line:
$file_name = str_replace(" ", "", $file_name);
Easy as that! Also remember, when you use the 2nd parameter in trim() you remove the "default" list of characters listed in the manual ( http://php.net/trim ) and replace it with your own ...
I would also point out, I would never use the filename as given by the browser in $_FILES[$x]['name'] ... It simply opens too many questions and possibilities up. One technique to avoid the issue altogether might be to simply use the md5() or sha1() or similar of the file's contents, example:
$file_name = md5_file($_FILES['your_file_tag_name']['tmp_name']);
That way in theory, you never ever have spaces in the files, or "dirty" filenames ... And in addition, if a user uploads two files with the precise same contents, you simply need to check for the file's existance, and if it already exists, you already have that exact same file. Hope this helps, this all assumes you're doing file uploads, which I'm not 100% certain you are.

Read a path stored in a text file and use it in opendir of PHP

I want to store a path (pointing to a directory) in a text file and open the path when required in PHP. Here's what I have done, which is quite simple but doesn't really work.
$dir = file_get_contents('./dir_file');
$dir_content = get_fname($dir);
function get_fname($dir) {
$dirhandle = opendir($dir);
if (!dirhandle) { exit; }
.........
}
The value of $dir is what it is in the text file. The code doesn't work. The function exits in the if statement.
I tried to replace the first line with
$dir = '/home/user/work'; //which is the path stored in the text file.
It works. So I suspect it's the problem of opendir. I can't figure out what causes this problem.
Any help will be appreciated. Many thanks.
Check if the file you're reading from has any line breaks, spaces, etc... after the actual path part. If you pass those in to opendir, it's going to look for a directory which has those literal characters in it, and most likely fail.
Adding a trim() call may help:
$dir = trim(file_get_contents('./dir_file'));
which will remove any such whitespace characters.

Php: is it safe to open a file with the fileName given through the url [if] filtered like this?

The url would be something like this:
www.example.com/index.php?file=myFile.ext
The filtering would only allow leters and numbers in the file, and only one dot.
The filtering would not give characters from the input to the file functions, instead, on for every allowed character it matches in an internal array, it copies the character from the internal array, and not the character from the input.
Ex:
if( isset(MyArray[inputChar]))
$fileName .= MyArray[inputChar]
This is especially to protect against weird encoding bugs, php bugs etc
The full example bellow (I used array_search() instead of isset()):
//split it to array of chars
$imputCharacters = str_split($_GET["file"]);
//splits it to array like this: [0] => 'a', [1] => 'b', etc
$allowedCharacters = str_split('1234567890abcdefghijklmnopqrstuvwxyz.ABCDEFGHIJKLMNOPQRSTUVWXYZ');
$file = '';
$dots = 0;
foreach ($imputCharacters as $char)
{
$indexKey = array_search($char, $allowedCharacters, true);
if($indexKey === false)
{
die(__FILE__ . __LINE__); // disalowed character
}
else
{
if ($allowedCharacters[$indexKey] === '.') {
$dots++;
if($dots > 1) {
die(__FILE__ . __LINE__); //only one dot allowed
}
}
$file .= $allowedCharacters[$indexKey];
}
}
Some other things you might want to watch out for:
Opening hidden files. You might not want to open your .svn or .hg files (Source control files).
URLs are case insensitive but they're case sensitive on the file system, so somehow accomodate for that?
Certain file names might having special meaning to the operating system? Such as the user providing a string that can be automatically decoded into something else on the filesystem?
Are you looking our for character encoding bugs? The user might supply the text in a specific encoding, which could be interpreted differently by the operating systems character encoding scheme.
Does the file exist?
Does it have some weird flag on it (Read-Only, Write-Only)?
Is the file readable by the web server's user account? I've run into issues with UNIX based systems where files are not readable by the www_root account that apache runs as.
I don't know how many of these are likely, just some things I've run across trying to solve similar problems.

Categories