我正在创建一个社交网络,我遇到了一些问题。
当我点击更改个人资料图片时,图片会转到目的地,然后没有任何反应。
我认为上传的图片有最大尺寸。如何给出一个告诉用户图像大的声明?
profile.php:
<form id="form2" action="upload.php" method="post" enctype="multipart/form-data">
<p id="p1">Change profile picture:</p> <br />
<input type="file" name="fileToUpload" id="fileToUpload"><br />
<br><input id="sub1" type="submit" value="Change profile picture" name="change"><br />
</form>
<!-- Trigger the Modal -->
<img id="myImg" src="default.png" width="200" height="150">
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- The Close Button -->
<span class="close" onclick="document.getElementById('myModal').style.display='none'">×</span>
<!-- Modal Content (The Image) -->
<img class="modal-content" id="img01">
<!-- Modal Caption (Image Text) -->
<div id="caption"></div>
</div>
<script>
// Get the modal
var modal = document.getElementById('myModal');
// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementById('myImg');
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
img.onclick = function(){
modal.style.display = "block";
modalImg.src = this.src;
captionText.innerHTML = this.alt;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
</script>
upload.php的:
$target_dir = "images/uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["change"])) {
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
$sql = "UPDATE users SET userPic = '".$_FILES['fileToUpload']['name']."' WHERE username = '" . $username . "'";
$check = $conn->query($sql);
if($check !== false) {
echo "<a href = profile.php> Profile pciture has been changed </a>" . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
} else {
echo"did not change";
}
答案 0 :(得分:3)
在您的HTML中,特别是这一行:
<img id="myImg" src="default.png" width="200" height="150">
您只需将图片设置为default.png
即可。除非发布的代码错误,否则我遗漏了一些东西。为什么这是你看到的唯一图像不应该是一个惊喜。
您需要从数据库中选择图像src值并将其添加到该标记。
所以你需要:
SELECT userPic FROM users WHERE username = :username
其中:user
是当前登录的用户ID。如果没有关于什么框架或您使用的DB库的更多信息,我可以为您提供更多帮助。例如,我不知道如何在登录后将会话数据保存在会话数据中,因此我无法知道如何获取它们的ID。我也不知道你是否使用PDO,MySqli甚至是你使用的数据库。
无论如何,我会添加一些我认为可以改进的东西。
在用户表中的用户表中,用于userPic字段。将默认值设置为default.png
,以便在添加新用户记录时该字段将包含默认图像。
非常重要在将输入连接到SQL的任何地方,更改为使用预准备语句。否则你要求被黑客攻击。请参阅Sql Injection攻击。
确保删除或覆盖旧图像。
如果用户B上传的图片名称相同,请确保用户A上传的图片无法覆盖。
我不会使用用户提供的图像名称。用户可以在那里放置各种垃圾。至少,用-
替换所有特殊字符和空格,然后减少-
。
像这样:
//note - remove the extension before doing this.
$str = 'dirty image name/.*';
$cleanname = trim(preg_replace(['/[^-\w]/', '/-{2,}/'], '-', $dirtyname),'-');
输出:
dirty-image-name
见live
我甚至让用户在文件名中添加引号,不知道他们是怎么做的,但我很难在Linux上删除这个文件。空间可以对网址造成严重破坏。看看网址,你通常不会看到任何空格或其他特殊字符。您还应该将time()
添加到图像,否则其他用户可能会覆盖另一个用户的图像。所以像$imagename = time().'-'.$imagename;
或者使用用户ID,这可能会更好。
正如我在评论中提到的,使用正确的命名约定,您甚至无需将图像名称保存在数据库中即可远离。如果您要像这样保存图像。
{$user_id}_profile.png
然后你可以检查:
$profileImage = "{$path}/{$user_id}_profile.png";
if(!file_exists($profileImage)){
$profileImage = "{$path}/default.png";
}
echo "<img src=\"{$profileImage}\" >";
此系统唯一的难点是将图像更改为PNG,但它具有处理文件名,覆盖问题以及将您存储在数据库中的优势。
修改图像并缩放图像或将其裁剪为您需要的尺寸并不是一个坏主意。这是我很久以前写的一个图像类。它没有100%完成,也没有真正记录。但它确实是我所知道的。在5年左右的时间里,我还没有做任何事情。但至少它应该给你一些关于如何裁剪,调整大小,转换图像等的想法。
https://github.com/ArtisticPhoenix/MISC/tree/master/Image
这个问题的范围有点深入到这个主题,但你更欢迎使用它,即使只是为了灵感。
快乐编码〜
您可以通过多种方式散列文件,
hash_file('sha256', $filepath)
hash('sha256', $filename)
如果SHA-256
很长,则可以使用sha1。可能甚至MD5
都可以工作,它们是64,40,长度是32。我发现SHA-1
比MD5
略快(当做超过10k的哈希时),我的意思是快几百分之一秒。
散列名称将比散列文件内容快得多。文件哈希可以有一些有用的应用程序,但它可能超出了这个问题的范围。基本上,你可以通过比较它的内容的散列来判断它是否是同一个文件。
在任何情况下,我都会添加一些特定于上传用户的标识符,例如用户名:
$filename = $username.'-'.hash('md5', $filename).$ext;
输出类似:
someuser-5d41402abc4b2a76b9719d911017c592.png
或者,您可以存储所有用户&#34; Stuff&#34;在以它们命名的文件夹中:
images/someuser
我甚至使用Zip存档来存储用户文件,这非常有效,但为应用程序增加了一点复杂性,因为当您想要保存文件并显示它们时,您必须压缩/解压缩文件。但它使文件系统上的所有内容都更加清晰。性能方面我没有注意到任何重大问题,但我在Azure上有一个非常强大的服务器(54GB内存)
我提到这些有几个原因:
您可以使用许多其他Algo进行散列,您可以使用hash_algos()
获取列表。散列越长,发生冲突的可能性越小或不同明文字符串的重复散列越少。您可以编写一个简单的循环来获取它们的长度:
foreach(hash_algos() AS $algo){
$hash = hash($algo, "hello");
echo "Algo:{$algo} Hash:{$hash} Len:".strlen($hash)."\n";
}
您可以看到此直播here
输出如下内容:
Algo:md2 Hash:a9046c73e00331af68917d3804f70655 Len:32
Algo:md4 Hash:866437cb7a794bce2b727acc0362ee27 Len:32
Algo:md5 Hash:5d41402abc4b2a76b9719d911017c592 Len:32
Algo:sha1 Hash:aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d Len:40
Algo:sha224 Hash:ea09ae9cc6768c50fcee903ed054556e5bfc8347907f12598aa24193 Len:56
Algo:sha256 Hash:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 Len:64
...
Algo:fnv1a64 Hash:a430d84680aabd0b Len:16
我甚至使用fnv1a64
进行文件名哈希(长度为16)。
您可能还希望存储文件的原始名称。通常我所做的是为user_files
设置一个表,然后我有一些这样的字段
id - Primary Auto Increment key
user_id - Foreign key for the user table
hashname - hashed name of the file ( - the extension )
filename - original filename
extension - file extension
status - status ( deleted | public | private )
type - type of image ( profile_image, thumb_60, thumb_128 )
create_date - date the record was created
所以我使用hashname
将其保存在硬盘驱动器上,但是当用户查看文件的名称时,我会以filename
方式向他们提供它们识别的名称,而不是我不得不解决与原始文件名相关的URL编码问题。 A&#34; Psudo&#34;链接到这样的文件将是:
<a href="{$imagepath}{$hashname}" >{$filename}</a>
永远不要存储&#34;路径名&#34;完整路径和文件名。仅存储文件名并使用代码指向路径。路径可能会随着时间的推移而发生变化,如果您存储它们,则可能必须在发生这些事件时更新所有数据库记录(或使用符号链接来使您的站点正常工作)。如果只存储文件名,则只需更改代码即可。
将用户信息放入&#34;路径&#34;也很重要,使用用户信息查找文件,然后根据该信息构建路径。您必须小心目录横向攻击。
https://en.wikipedia.org/wiki/Directory_traversal_attack
这就是散列文件名是个好主意的原因。
您还可以将保存哈希值的字段的排序规则更改为UTF8_bin
,即UTF8二进制文件。这样做是为了使该字段的搜索区分大小写。哈希区分大小写。这是一件经常被忽视的小事。所以,我不会说这是必要的,但这是一个很好的做法,可以告诉你你在做什么。此外,散列的长度越小,它变得越重要。
有关此文件:
https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html
如果您希望始终以区分大小写的方式处理列,请使用区分大小写或二进制排序规则来声明它
我知道要考虑到这一点很多,但是真的值得做好。
正如您在评论中提到的那样,您可以使用uniqid
,但我仍然强烈建议为每个用户添加一条信息,这可以通过为其添加前缀来完成。
$username = 'someuser';
uniqid($username.'-');
输出:
someuser-5a5a847a96c76
这个的主要原因(正如我前面提到的)是你需要100%确定一个用户不能覆盖另一个用户数据。 uniqid
未得到保证&#34;在100%的时间内制作独特的价值。
http://php.net/manual/en/function.uniqid.php
警告此函数尝试创建唯一标识符,但不保证返回值的100%唯一性。
应该极其谨慎地保护从一个帐户到另一个帐户的交叉污染。如果不这样做,将会摧毁任何信仰&#34;用户拥有您系统的安全性。这似乎是一个微不足道的风险,但如果它发生将是非常糟糕的。我知道我不会使用我的信息可以从我的帐户泄漏到另一个帐户的网站。