package org.develnext.jphp.zend.ext.standard;
import php.runtime.Memory;
import php.runtime.common.StringUtils;
import php.runtime.env.Environment;
import php.runtime.env.TraceInfo;
import php.runtime.ext.core.classes.stream.Stream;
import php.runtime.ext.core.classes.stream.WrapIOException;
import php.runtime.ext.support.compile.FunctionsContainer;
import php.runtime.invoke.ObjectInvokeHelper;
import php.runtime.memory.*;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.*;
import java.util.*;
import static org.develnext.jphp.zend.ext.standard.FileConstants.*;
import static php.runtime.annotation.Runtime.Immutable;
public class FileFunctions extends FunctionsContainer {
@Immutable
public static String basename(String path, String suffix) {
String result = new File(path).getName();
if (suffix != null && !suffix.isEmpty() && result.endsWith(suffix))
result = result.substring(0, result.length() - suffix.length());
return result;
}
@Immutable
public static String basename(String path) {
return basename(path, null);
}
public static boolean chgrp(String fileName, Memory group) {
return false;
}
public static boolean copy(Environment env, TraceInfo trace, String source, String dest) throws Throwable {
Stream stream = Stream.create(env, source, "r");
if (stream == null) {
env.warning("copy(): Invalid source path");
return false;
}
Memory value = stream.readFully(env);
RandomAccessFile outputStream;
try {
outputStream = new RandomAccessFile(dest, "rw");
} catch (FileNotFoundException e) {
return false;
}
try {
outputStream.setLength(0);
outputStream.write(value.getBinaryBytes(env.getDefaultCharset()));
return true;
} catch (IOException e) {
env.warning("copy(): " + e.getMessage());
return false;
} finally {
try {
outputStream.close();
} catch (IOException e) {
return false;
}
}
}
@Immutable
public static String dirname(String path) {
String r = new File(path).getParent();
if (r == null)
return "";
return r;
}
public static Memory disk_free_space(String path) {
return LongMemory.valueOf(new File(path).getFreeSpace());
}
public static Memory disk_total_space(String path) {
return LongMemory.valueOf(new File(path).getTotalSpace());
}
public static Memory diskfreespace(String path) {
return disk_free_space(path);
}
public static boolean file_exists(String path) {
return new File(path).getAbsoluteFile().exists();
}
public static Memory file(Environment env, TraceInfo trace, String path, int flags) throws Throwable {
return file(env, trace, path, flags, Memory.NULL);
}
public static Memory file(Environment env, TraceInfo trace, String path) throws Throwable {
return file(env, trace, path, 0, Memory.NULL);
}
public static Memory file(Environment env, TraceInfo trace, String path, int flags, Memory context) throws Throwable {
Stream stream = null;
try {
stream = Stream.create(env, path, "r");
if (stream == null) {
env.warning(trace, "file(): failed to open stream");
return Memory.FALSE;
}
stream.setContext(env, context);
Memory value = env.invokeMethod(trace, stream, "readFully");
byte[] bytes = value.getBinaryBytes(env.getDefaultCharset());
ArrayMemory result = new ArrayMemory();
int prev = 0;
boolean ignoreNewLines = (flags & FileConstants.FILE_IGNORE_NEW_LINES) == FileConstants.FILE_IGNORE_NEW_LINES;
int i;
for (i = 0; i < bytes.length; i++) {
byte ch = bytes[i];
if (ch == '\n') {
if (prev == i && (flags & FileConstants.FILE_SKIP_EMPTY_LINES) == FileConstants.FILE_SKIP_EMPTY_LINES) {
prev += 1;
continue;
}
byte[] chunk = ignoreNewLines ? Arrays.copyOfRange(bytes, prev, i - 1) : Arrays.copyOfRange(bytes, prev, i);
prev = i + 1;
result.add(new BinaryMemory(chunk));
}
}
if (prev != i) {
byte[] chunk = Arrays.copyOfRange(bytes, prev, i);
result.add(new BinaryMemory(chunk));
}
return result.toConstant();
} catch (WrapIOException e) {
if (stream == null && (flags & FileConstants.FILE_USE_INCLUDE_PATH) == FileConstants.FILE_USE_INCLUDE_PATH) {
path = env.findInIncludePaths(path);
if (path != null)
return file(env, trace, path, flags ^ FileConstants.FILE_USE_INCLUDE_PATH, context);
}
env.warning(trace, "file(): " + e.getMessage());
return Memory.FALSE;
} finally {
if (stream != null)
stream.close(env);
}
}
public static Memory file_get_contents(Environment env, TraceInfo trace, String path, boolean useIncludePaths,
Memory context, Memory offset, Memory maxLength) throws Throwable {
Stream stream = null;
try {
stream = Stream.create(env, path, "r");
if (stream == null) {
env.warning(trace, "file_get_contents(): failed to open stream");
return Memory.FALSE;
}
stream.setContext(env, context);
if (offset.toLong() > 0)
stream.seek(env, offset);
if (maxLength.isNull())
return stream.readFully(env, LongMemory.valueOf(4096));
else
return stream.read(env, maxLength);
} catch (WrapIOException | IOException e) {
if (stream == null && useIncludePaths) {
path = env.findInIncludePaths(path);
if (path != null)
return file_get_contents(env, trace, path, false, context, offset, maxLength);
}
env.warning(trace, "file_get_contents(): " + e.getMessage());
return Memory.FALSE;
} finally {
if (stream != null)
stream.close(env);
}
}
public static Memory file_get_contents(Environment env, TraceInfo trace, String path, boolean useIncludePaths,
Memory context, Memory offset) throws Throwable {
return file_get_contents(env, trace, path, useIncludePaths, context, offset, Memory.NULL);
}
public static Memory file_get_contents(Environment env, TraceInfo trace, String path, boolean useIncludePaths,
Memory context) throws Throwable {
return file_get_contents(env, trace, path, useIncludePaths, context, Memory.CONST_INT_M1, Memory.NULL);
}
public static Memory file_get_contents(Environment env, TraceInfo trace, String path, boolean useIncludePaths) throws Throwable {
return file_get_contents(env, trace, path, useIncludePaths, Memory.NULL, Memory.CONST_INT_M1, Memory.NULL);
}
public static Memory file_get_contents(Environment env, TraceInfo trace, String path) throws Throwable {
return file_get_contents(env, trace, path, true, Memory.NULL, Memory.CONST_INT_M1, Memory.NULL);
}
public static Memory file_put_contents(Environment env, TraceInfo trace, String path, Memory data, int flags,
Memory context) throws Throwable {
Stream stream = null;
try {
String mode = "w";
if ((flags & FileConstants.FILE_APPEND) == FileConstants.FILE_APPEND)
mode = "a";
stream = Stream.create(env, path, mode);
if (stream == null) {
env.warning(trace, "file_put_contents(): failed to open stream");
return Memory.FALSE;
}
stream.setContext(env, context);
if (data.instanceOf(Stream.CLASS_NAME)) {
data = env.invokeMethod(trace, data, "readFully");
}
return stream.write(env, data, Memory.NULL);
} catch (WrapIOException e) {
env.warning(trace, "file_put_contents(): " + e.getMessage());
return Memory.FALSE;
} finally {
if (stream != null)
stream.close(env);
}
}
public static Memory file_put_contents(Environment env, TraceInfo trace, String path, Memory data, int flags)
throws Throwable {
return file_put_contents(env, trace, path, data, flags, Memory.NULL);
}
public static Memory file_put_contents(Environment env, TraceInfo trace, String path, Memory data)
throws Throwable {
return file_put_contents(env, trace, path, data, 0, Memory.NULL);
}
public static boolean is_dir(String path) {
return new File(path).isDirectory();
}
public static boolean is_file(String path) {
return new File(path).isFile();
}
public static boolean is_link(String path) {
try {
File file = new File(path);
File canon;
if (file.getParent() == null) {
canon = file;
} else {
File canonDir = file.getParentFile().getCanonicalFile();
canon = new File(canonDir, file.getName());
}
return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
} catch (IOException e) {
return false;
}
}
public static boolean is_executable(String path) {
return new File(path).canExecute();
}
public static boolean is_readable(String path) {
return new File(path).canRead();
}
public static boolean is_writable(String path) {
return new File(path).canWrite();
}
public static boolean is_writeable(String path) {
return new File(path).canWrite();
}
public static boolean mkdir(String path, int mode, boolean recursive) {
if (recursive)
return new File(path).mkdirs();
else
return new File(path).mkdir();
}
public static boolean mkdir(String path, int mode) {
return mkdir(path, mode, false);
}
public static boolean mkdir(String path) {
return mkdir(path, 777, false);
}
public static Memory filemtime(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
return LongMemory.valueOf(Files.getLastModifiedTime(file).toMillis() / 1000);
} catch (IOException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory fileatime(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
return LongMemory.valueOf(attributes.lastAccessTime().toMillis() / 1000);
} catch (IOException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory filectime(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
return LongMemory.valueOf(attributes.creationTime().toMillis() / 1000);
} catch (IOException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory filesize(Environment env, TraceInfo trace, String path) {
try {
return LongMemory.valueOf(new File(path).length());
} catch (Exception e) {
env.warning(trace, "filesize(): file not found - %s", path);
return Memory.FALSE;
}
}
public static Memory filetype(Environment env, TraceInfo trace, String path) {
File file = new File(path);
if (file.isFile())
return new StringMemory("file");
else if (file.isDirectory())
return new StringMemory("dir");
else {
try {
BasicFileAttributes attributes = Files.readAttributes(Paths.get(path), BasicFileAttributes.class);
if (attributes.isSymbolicLink()) {
return new StringMemory("link");
}
return new StringMemory("unknown");
} catch (IOException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
}
}
}
public static Memory filegroup(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
int attribute = (int) Files.getAttribute(file, "unix:gid");
return LongMemory.valueOf(attribute);
} catch (IOException|SecurityException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory fileowner(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
int attribute = (int) Files.getAttribute(file, "unix:uid");
return LongMemory.valueOf(attribute);
} catch (IOException|SecurityException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory fileperms(Environment env, TraceInfo trace, String path) {
Path file = Paths.get(path);
try {
int attribute = (int) Files.getAttribute(file, "unix:mode");
return LongMemory.valueOf(attribute);
} catch (IOException|SecurityException e) {
env.warning(trace, e.getMessage());
return Memory.FALSE;
} catch (UnsupportedOperationException e) {
return Memory.FALSE;
}
}
public static Memory pathinfo(String path, int options) {
File file = new File(path);
ArrayMemory result = new ArrayMemory();
String basename = file.getName();
int pos = basename.lastIndexOf('.');
String ext = null;
if (pos > -1)
ext = basename.substring(pos + 1);
if ((options & PATHINFO_DIRNAME) == PATHINFO_DIRNAME)
result.refOfIndex("dirname").assign(file.getParent());
if ((options & PATHINFO_DIRNAME) == PATHINFO_DIRNAME)
result.refOfIndex("basename").assign(file.getName());
if (ext != null && (options & PATHINFO_EXTENSION) == PATHINFO_EXTENSION)
result.refOfIndex("extension").assign(ext);
if ((options & PATHINFO_FILENAME) == PATHINFO_FILENAME)
result.refOfIndex("filename").assign(pos > -1 ? basename.substring(0, pos) : basename);
return result.toConstant();
}
public static Memory pathinfo(String path) {
return pathinfo(path, PATHINFO_BASENAME | PATHINFO_DIRNAME | PATHINFO_EXTENSION | PATHINFO_FILENAME);
}
public static boolean rename(String oldname, String newname) {
try {
return new File(oldname).renameTo(new File(newname));
} catch (Exception e) {
return false;
}
}
public static boolean rmdir(String path) {
File file = new File(path);
if (file.isDirectory()) {
try {
return file.delete();
} catch (Exception e) {
return false;
}
} else
return false;
}
public static boolean unlink(String path) {
File file = new File(path);
if (file.isDirectory())
return false;
try {
return file.delete();
} catch (Exception e) {
return false;
}
}
public static boolean touch(Environment env, TraceInfo trace, String path, long time, long atime) {
File file = new File(path);
if (!file.exists())
try {
if (!file.createNewFile())
return false;
} catch (IOException e) {
env.warning(trace, e.getMessage());
return false;
}
return file.setLastModified(time * 1000);
}
public static boolean touch(Environment env, TraceInfo trace, String path, long time) {
return touch(env, trace, path, time, 0);
}
public static boolean touch(Environment env, TraceInfo trace, String path) {
return touch(env, trace, path, System.currentTimeMillis() / 1000, 0);
}
public static Memory tempnam(String dir, String prefix) {
try {
return new StringMemory(File.createTempFile(prefix, "", new File(dir)).getPath());
} catch (IOException e) {
return Memory.FALSE;
}
}
public static Memory realpath(String path) {
try {
return new StringMemory(new File(path).getCanonicalPath());
} catch (IOException e) {
return Memory.FALSE;
}
}
public static Memory readfile(Environment env, TraceInfo trace, String path, boolean useIncludePaths,
Memory stream) throws Throwable {
File file = new File(path);
if (useIncludePaths && !file.exists()) {
path = env.findInIncludePaths(path);
if (path == null)
return Memory.FALSE;
file = new File(path);
}
try {
RandomAccessFile accessFile = new RandomAccessFile(file, "r");
try {
if (!stream.isNull()) {
if (!stream.instanceOf(Stream.CLASS_NAME)) {
env.warning(trace, "readfile(): Argument 3 must be stream, %s given", stream.getRealType().toString());
return Memory.FALSE;
}
byte[] buff = new byte[4096];
int len = 0;
int read = 0;
while ((len = accessFile.read(buff)) != -1) {
read += len;
ObjectInvokeHelper.invokeMethod(
stream, "write", env, trace, new BinaryMemory(buff), LongMemory.valueOf(len)
);
}
return LongMemory.valueOf(read);
} else {
byte[] buff = new byte[4096];
int len = 0;
int read = 0;
while ((len = accessFile.read(buff)) != -1) {
read += len;
env.echo(buff, len);
}
return LongMemory.valueOf(read);
}
} finally {
accessFile.close();
}
} catch (FileNotFoundException e) {
env.warning(trace, "readfile(): File not found - %s", path);
return Memory.FALSE;
} catch (IOException e) {
env.warning(trace, "readfile(): %s", e.getMessage());
return Memory.FALSE;
}
}
public static Memory readfile(Environment env, TraceInfo trace, String path, boolean useIncludePaths)
throws Throwable {
return readfile(env, trace, path, useIncludePaths, Memory.NULL);
}
public static Memory readfile(Environment env, TraceInfo trace, String path)
throws Throwable {
return readfile(env, trace, path, false, Memory.NULL);
}
public static Memory fopen(Environment env, TraceInfo trace, String path, String mode) {
try {
return ObjectMemory.valueOf(Stream.create(env, path, mode));
} catch (Throwable throwable) {
env.warning(trace, "fopen(): failed to open stream, " + throwable.getMessage());
return Memory.FALSE;
}
}
public static Memory ftell(Environment env, TraceInfo trace, Memory stream) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
return env.invokeMethod(trace, stream, "getPosition");
} catch (Throwable throwable) {
env.warning(trace, "ftell(): " + throwable.getMessage());
return Memory.FALSE;
}
}
env.warning(trace, "ftell(): unable to get position from a non-stream");
return Memory.FALSE;
}
public static Memory feof(Environment env, TraceInfo trace, Memory stream) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
return env.invokeMethod(trace, stream, "eof");
} catch (Throwable throwable) {
env.warning(trace, "feof(): " + throwable.getMessage());
return Memory.FALSE;
}
}
env.warning(trace, "feof(): unable get eof from a non-stream");
return Memory.FALSE;
}
public static Memory fread(Environment env, TraceInfo trace, Memory stream, int length) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
return env.invokeMethod(trace, stream, "read", LongMemory.valueOf(length));
} catch (Throwable throwable) {
env.warning(trace, "fread(): " + throwable.getMessage());
return Memory.FALSE;
}
}
env.warning(trace, "fread(): unable to read from a non-stream");
return Memory.FALSE;
}
public static Memory fgetc(Environment env, TraceInfo trace, Memory stream) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
Memory memory = env.invokeMethod(trace, stream, "read", Memory.CONST_INT_1);
return memory.isNull() ? Memory.FALSE : memory;
} catch (Throwable throwable) {
env.warning(trace, "fgetc(): " + throwable.getMessage());
return Memory.FALSE;
}
}
env.warning(trace, "fgetc(): unable to read from a non-stream");
return Memory.FALSE;
}
public static Memory fseek(Environment env, TraceInfo trace, Memory stream, long offset) {
return fseek(env, trace, stream, offset, 0);
}
public static Memory fseek(Environment env, TraceInfo trace, Memory stream, long offset, int whence) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
switch (whence) {
case 1:
offset += env.invokeMethod(trace, stream, "getPosition").toLong();
break;
case 2:
env.error(trace, "fseek(): flag SEEK_END is not supported.");
break;
default:
case 0:
break;
}
env.invokeMethod(trace, stream, "seek", LongMemory.valueOf(offset));
return Memory.CONST_INT_0;
} catch (Throwable throwable) {
env.warning(trace, "fseek(): " + throwable.getMessage());
return Memory.CONST_INT_M1;
}
}
env.warning(trace, "fseek(): unable to seek in a non-stream");
return Memory.CONST_INT_M1;
}
public static Memory fputs(Environment env, TraceInfo trace, Memory stream, Memory value) {
return fwrite(env, trace, stream, value);
}
public static Memory fputs(Environment env, TraceInfo trace, Memory stream, Memory value, Memory length) {
return fwrite(env, trace, stream, value, length);
}
public static Memory fgets(Environment env, TraceInfo trace, Memory stream) {
return fgets(env, trace, stream, Memory.NULL);
}
public static Memory fgets(Environment env, TraceInfo trace, Memory stream, Memory length) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
InputStream in = Stream.getInputStream(env, stream);
if (in != null) {
int read;
StringBuilder sb = new StringBuilder();
try {
while ((read = in.read()) != -1) {
if (length.isNotNull() && sb.length() >= length.toInteger()) {
break;
}
if (read == '\n' || read == '\r') {
break;
}
sb.append((char) read);
}
return StringMemory.valueOf(sb.toString());
} catch (IOException e) {
env.warning(trace, "fgets(): " + e.getMessage());
return Memory.FALSE;
}
}
}
env.warning(trace, "fgets(): unable to get from a non-stream");
return Memory.FALSE;
}
public static Memory fwrite(Environment env, TraceInfo trace, Memory stream, Memory value) {
return fwrite(env, trace, stream, value, Memory.NULL);
}
public static Memory fwrite(Environment env, TraceInfo trace, Memory stream, Memory value, Memory length) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
return env.invokeMethod(trace, stream, "write", value, length);
} catch (Throwable throwable) {
env.warning(trace, "fwrite(): " + throwable.getMessage());
return Memory.FALSE;
}
}
env.warning(trace, "fwrite(): unable to write to a non-stream");
return Memory.FALSE;
}
public static Memory fclose(Environment env, TraceInfo trace, Memory stream) {
if (stream.instanceOf(Stream.CLASS_NAME)) {
try {
env.invokeMethod(trace, stream, "close");
return Memory.TRUE;
} catch (Throwable throwable) {
return Memory.FALSE;
}
} else {
env.warning("fclose(): unable to close a non-stream");
return Memory.FALSE;
}
}
public static String getcwd() {
Path currentRelativePath = Paths.get("");
return currentRelativePath.toAbsolutePath().toString();
}
public static String getenv(Environment env, String name) {
Map<String, String> zendEnv = env.getUserValue("env", Map.class);
if (zendEnv != null) {
String s = zendEnv.get(name);
if (s != null) {
return s;
}
}
return System.getenv(name);
}
synchronized public static void putenv(Environment env, String _value) {
if (_value.isEmpty()) {
return;
}
String[] strings = StringUtils.split(_value, "=", 2);
String name = strings[0];
String value = strings.length > 1 ? strings[1] : null;
Map<String, String> zendEnv = env.getUserValue("env", Map.class);
if (zendEnv == null) {
env.setUserValue("env", zendEnv = new HashMap<String, String>());
}
if (value == null) {
zendEnv.remove(name);
} else {
zendEnv.put(name, value);
}
}
public static Memory scandir(String path, int order) {
ArrayMemory r = new ArrayMemory();
String[] list = new File(path).list();
switch (order) {
case FileConstants.SCANDIR_SORT_DESCENDING:
Arrays.sort(list, Collections.reverseOrder());
for (String s : list) { r.add(s); }
r.add("..");
r.add(".");
break;
case FileConstants.SCANDIR_SORT_ASCENDING:
r.add(".");
r.add("..");
Arrays.sort(list);
for (String s : list) { r.add(s); }
break;
default:
r.add(".");
r.add("..");
for (String s : list) { r.add(s); }
break;
}
return r.toConstant();
}
public static Memory scandir(String path) {
return scandir(path, FileConstants.SCANDIR_SORT_ASCENDING);
}
}