bool is_writable ( string $filename )
别名函数:is_writeable()(拼写不同,功能相同)
| 参数 | 描述 |
|---|---|
| filename | 必需。规定要检查的文件或目录路径。 |
is_writable() 不仅可以检查文件,也可以检查目录是否可写。如果路径是目录,函数检查是否可以在该目录中创建或修改文件。
如果文件或目录存在并且可写,返回 TRUE,否则返回 FALSE。
检查文件是否可写:
<?php
$filename = 'data.log';
if (is_writable($filename)) {
echo "文件 '$filename' 可写。";
// 尝试写入文件
if (file_put_contents($filename, "写入时间: " . date('Y-m-d H:i:s') . "\n", FILE_APPEND)) {
echo "<br>数据已成功追加到文件。";
} else {
echo "<br>写入文件失败。";
}
} else {
echo "文件 '$filename' 不可写或不存在。";
// 检查文件是否存在
if (file_exists($filename)) {
echo "<br>文件存在,但没有写入权限。";
// 显示当前权限
$perms = fileperms($filename);
echo "<br>文件权限: " . substr(sprintf('%o', $perms), -4);
}
}
?>
检查目录是否可写(用于文件上传或创建临时文件):
<?php
$directory = 'uploads';
// 创建目录(如果不存在)
if (!file_exists($directory)) {
if (mkdir($directory, 0755, true)) {
echo "已创建目录: $directory<br>";
} else {
echo "创建目录失败: $directory<br>";
}
}
echo "检查目录可写性:<br><br>";
// 检查目录是否可写
if (is_writable($directory)) {
echo "✓ 目录 '$directory' 可写。<br>";
// 尝试在目录中创建测试文件
$test_file = $directory . '/test_' . time() . '.txt';
if (file_put_contents($test_file, '测试内容')) {
echo "✓ 成功在目录中创建测试文件: " . basename($test_file) . "<br>";
// 清理测试文件
unlink($test_file);
echo "✓ 已清理测试文件。<br>";
} else {
echo "✗ 在目录中创建文件失败。<br>";
}
} else {
echo "✗ 目录 '$directory' 不可写。<br>";
// 显示目录信息
if (is_dir($directory)) {
echo "- 这是一个目录。<br>";
$perms = fileperms($directory);
echo "- 目录权限: " . substr(sprintf('%o', $perms), -4) . "<br>";
echo "- 目录所有者: " . fileowner($directory) . "<br>";
echo "- 建议使用: chmod('$directory', 0755) 或 chmod('$directory', 0777)<br>";
}
}
?>
综合检查文件的多种状态,包括可读性、可写性等:
<?php
function checkFileStatus($path) {
$results = [];
// 清除缓存,获取最新状态
clearstatcache();
$results['path'] = $path;
$results['exists'] = file_exists($path);
if ($results['exists']) {
$results['is_file'] = is_file($path);
$results['is_dir'] = is_dir($path);
$results['is_link'] = is_link($path);
$results['is_readable'] = is_readable($path);
$results['is_writable'] = is_writable($path);
$results['is_executable'] = is_executable($path);
$results['size'] = filesize($path);
$results['modified_time'] = date('Y-m-d H:i:s', filemtime($path));
$results['permissions'] = substr(sprintf('%o', fileperms($path)), -4);
$results['owner'] = fileowner($path);
$results['group'] = filegroup($path);
}
return $results;
}
// 检查多个文件/目录
$paths = [
'config.ini',
'uploads/',
'/tmp',
'readonly.txt',
'nonexistent.txt'
];
echo "文件/目录状态检查报告:<br><br>";
foreach ($paths as $path) {
$status = checkFileStatus($path);
echo "<div class='mb-3 p-3 border rounded'>";
echo "<h5><code>$path</code></h5>";
if ($status['exists']) {
echo "类型: ";
if ($status['is_file']) echo "文件";
if ($status['is_dir']) echo "目录";
if ($status['is_link']) echo " (符号链接)";
echo "<br>";
echo "大小: " . ($status['is_dir'] ? '-' : number_format($status['size']) . " 字节") . "<br>";
echo "修改时间: " . $status['modified_time'] . "<br>";
echo "权限: " . $status['permissions'] . "<br>";
echo "所有者/组: " . $status['owner'] . "/" . $status['group'] . "<br><br>";
echo "访问权限:<br>";
echo "可读: " . ($status['is_readable'] ? "✓" : "✗") . "<br>";
echo "可写: " . ($status['is_writable'] ? "✓" : "✗") . "<br>";
echo "可执行: " . ($status['is_executable'] ? "✓" : "✗") . "<br>";
} else {
echo "✗ 文件/目录不存在<br>";
}
echo "</div>";
}
?>
在写入文件前验证可写性并处理可能的问题:
<?php
function safeWriteToFile($filename, $content, $mode = 'w') {
// 清除缓存
clearstatcache();
// 检查目录是否存在并可写
$dir = dirname($filename);
if (!file_exists($dir)) {
// 尝试创建目录
if (!mkdir($dir, 0755, true)) {
return ['success' => false, 'error' => "无法创建目录: $dir"];
}
}
if (!is_writable($dir)) {
return ['success' => false, 'error' => "目录不可写: $dir"];
}
// 如果文件存在,检查是否可写
if (file_exists($filename) && !is_writable($filename)) {
return ['success' => false, 'error' => "文件存在但不可写: $filename"];
}
// 使用文件锁安全写入
$handle = fopen($filename, $mode);
if (!$handle) {
return ['success' => false, 'error' => "无法打开文件: $filename"];
}
// 尝试获取独占锁(LOCK_EX)
if (flock($handle, LOCK_EX)) {
$bytes_written = fwrite($handle, $content);
flock($handle, LOCK_UN);
fclose($handle);
if ($bytes_written === false) {
return ['success' => false, 'error' => "写入文件失败"];
}
return [
'success' => true,
'bytes_written' => $bytes_written,
'file_size' => filesize($filename)
];
} else {
fclose($handle);
return ['success' => false, 'error' => "无法获取文件锁"];
}
}
// 使用示例
$result = safeWriteToFile('logs/app.log', "日志条目: " . date('Y-m-d H:i:s') . "\n", 'a');
if ($result['success']) {
echo "文件写入成功!<br>";
echo "写入字节数: " . $result['bytes_written'] . "<br>";
echo "文件总大小: " . $result['file_size'] . " 字节";
} else {
echo "文件写入失败!<br>";
echo "错误: " . $result['error'] . "<br><br>";
// 尝试修复建议
$filename = 'logs/app.log';
echo "建议解决方案:<br>";
echo "1. 检查目录权限: chmod('logs', 0755)<br>";
echo "2. 检查文件权限: chmod('$filename', 0644)<br>";
echo "3. 检查磁盘空间: disk_free_space('.')<br>";
echo "4. 检查文件是否被其他进程锁定<br>";
}
?>
诊断和解决文件/目录不可写的问题:
<?php
function diagnoseWritePermission($path) {
$diagnosis = [];
echo "权限诊断报告: <code>$path</code><br><br>";
// 检查路径是否存在
if (!file_exists($path)) {
echo "1. 路径不存在。<br>";
echo " - 如果是文件,需要创建文件<br>";
echo " - 如果是目录,使用 mkdir('$path', 0755, true) 创建<br><br>";
return;
}
// 检查基本可写性
echo "1. is_writable() 结果: " . (is_writable($path) ? "✓ 可写" : "✗ 不可写") . "<br><br>";
// 获取详细信息
$perms = fileperms($path);
$permString = substr(sprintf('%o', $perms), -4);
$owner = fileowner($path);
$group = filegroup($path);
echo "2. 权限详细信息:<br>";
echo " - 权限: $permString<br>";
echo " - 所有者: $owner<br>";
echo " - 所属组: $group<br><br>";
// 分析权限
echo "3. 权限分析:<br>";
$is_dir = is_dir($path);
$type = $is_dir ? "目录" : "文件";
// 检查所有者权限
$ownerPerm = (int)$permString[1];
if ($ownerPerm >= 6) {
echo " - 所有者有读写权限 (✓)<br>";
} elseif ($ownerPerm >= 4) {
echo " - 所有者只有读权限,没有写权限 (✗)<br>";
} else {
echo " - 所有者没有读写权限 (✗)<br>";
}
// 检查Web服务器用户
echo "4. Web服务器用户信息:<br>";
echo " - 当前用户ID: " . getmyuid() . "<br>";
echo " - 当前进程ID: " . getmypid() . "<br>";
echo " - 脚本所有者: " . get_current_user() . "<br><br>";
// 检查父目录权限
if (!$is_dir) {
$parentDir = dirname($path);
echo "5. 父目录检查 (<code>$parentDir</code>): <br>";
if (is_writable($parentDir)) {
echo " - 父目录可写 (✓)<br>";
} else {
echo " - 父目录不可写 (✗)<br>";
echo " - 即使文件可写,也需要父目录可写才能创建/删除文件<br>";
}
}
echo "<br>6. 建议解决方案:<br>";
if ($is_dir) {
echo " - 修改目录权限: <code>chmod('$path', 0755);</code><br>";
echo " - 修改目录所有者为Web服务器用户<br>";
echo " - 确保SELinux/AppArmor允许Web服务器写入该目录<br>";
} else {
echo " - 修改文件权限: <code>chmod('$path', 0644);</code><br>";
echo " - 如果文件只读,尝试: <code>chmod('$path', 0666);</code><br>";
echo " - 检查文件是否被其他进程锁定<br>";
}
echo " - 检查磁盘空间: <code>disk_free_space('.')</code><br>";
}
// 使用示例
diagnoseWritePermission('important_data.txt');
?>
clearstatcache() 清除缓存。
检查文件是否可读
检查文件或目录是否存在
改变文件权限
打开文件或URL
将字符串写入文件
便携式文件锁定
创建目录
设置文件的访问和修改时间