summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2025-07-23 18:45:43 +0200
committerDaniel Weipert <git@mail.dweipert.de>2025-07-23 18:45:43 +0200
commit0eccccfab33bbad8d5731700c1ed959debe98bbd (patch)
tree3a0623d996803b6cc0669c0489db1a26560650e6
parentd51eee7ed707568f58d305abb750349cb2f27bcc (diff)
display blob based on mime type
-rw-r--r--index.php178
1 files changed, 148 insertions, 30 deletions
diff --git a/index.php b/index.php
index d45341a..1dddf72 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,11 @@
<?php
+
+##
+# Git
+##
+
+
/**
* find projects at $path
*
@@ -7,12 +13,18 @@
*/
function find_projects(string $path, array $projects = []): array {
$directories = glob($path . "/{.[!.],}*", GLOB_ONLYDIR | GLOB_BRACE);
- if (($idx = array_search("$path/.git", $directories)) !== false) {
- $projects[] = substr($directories[$idx], 0, -4);
+
+ if (array_search("$path/.git", $directories) !== false) {
+ $projects[] = $path;
}
else {
- foreach ($directories as $directory) {
- $projects += find_projects($directory, $projects);
+ if (count(array_intersect(scandir($path), ["HEAD", "objects", "refs"])) == 3) {
+ $projects[] = $path;
+ }
+ else {
+ foreach ($directories as $directory) {
+ $projects += find_projects($directory, $projects);
+ }
}
}
@@ -53,6 +65,7 @@ function parse_log(string $path): array {
return $cache_parse_log[$path] = $json ?? [];
}
+
/**
* parse git status at $path
*/
@@ -138,6 +151,7 @@ function parse_status(string $path): array {
return $status;
}
+
/**
* get git file tree at $path for $revision under $tree_base_path
*/
@@ -145,7 +159,7 @@ function get_file_tree(string $path, string $revision, string $tree_base_path):
{
$proxy = md5(strval(microtime(true)));
$process = proc_open(
- "git -C \"{$path}\" ls-tree {$revision} {$tree_base_path}" . " --format='{%n {$proxy}mode{$proxy}: {$proxy}%(objectmode){$proxy},%n {$proxy}type{$proxy}: {$proxy}%(objecttype){$proxy},%n {$proxy}name{$proxy}: {$proxy}%(objectname){$proxy},%n {$proxy}size{$proxy}: {$proxy}%(objectsize){$proxy},%n {$proxy}path{$proxy}: {$proxy}%(path){$proxy}%n},'",
+ "git -C \"{$path}\" ls-tree {$revision} \"{$tree_base_path}\"" . " --format='{%n {$proxy}mode{$proxy}: {$proxy}%(objectmode){$proxy},%n {$proxy}type{$proxy}: {$proxy}%(objecttype){$proxy},%n {$proxy}name{$proxy}: {$proxy}%(objectname){$proxy},%n {$proxy}size{$proxy}: {$proxy}%(objectsize){$proxy},%n {$proxy}path{$proxy}: {$proxy}%(path){$proxy}%n},'",
[
["pipe", "r"],
["pipe", "w"],
@@ -165,6 +179,69 @@ function get_file_tree(string $path, string $revision, string $tree_base_path):
/**
+ * get git file info for single file at $file_path in repository at $path
+ */
+function get_file_info(string $path, string $file_path): array
+{
+ $tree = get_file_tree($path, "HEAD", $file_path);
+
+ $info = [];
+ foreach ($tree as $file) {
+ if ($file["path"] == $file_path) {
+ $info = $file;
+ break;
+ }
+ }
+
+ return $info;
+}
+
+
+/**
+ * get file contents based on $name (git object id) in repository at $path
+ */
+function read_object_file(string $path, string $name): string
+{
+ $process = proc_open(
+ "git -C \"{$path}\" cat-file -p \"{$name}\"",
+ [
+ ["pipe", "r"],
+ ["pipe", "w"],
+ ["pipe", "w"],
+ ],
+ $pipes
+ );
+
+ return stream_get_contents($pipes[1]);
+}
+
+
+##
+# Utility
+##
+
+
+/**
+ * urlencode whole $url
+ */
+function uri_encode(string $url): string
+{
+ return implode(
+ "/",
+ array_map(
+ fn ($value) => urlencode($value),
+ explode("/", $url)
+ )
+ );
+}
+
+
+##
+# Template
+##
+
+
+/**
* Template root
*/
function template_root(string $content, array $meta = []): string
@@ -180,12 +257,17 @@ function template_root(string $content, array $meta = []): string
<html>
<head>
<title><?php echo $meta["title"]; ?></title>
+ <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
<style>
.blob-code-block {
pre {
border: 1px solid;
display: inline-block;
padding: 1rem;
+ box-sizing: border-box;
+ max-width: 100vw;
+ white-space: pre-wrap;
+ word-break: break-word;
}
}
</style>
@@ -198,6 +280,34 @@ function template_root(string $content, array $meta = []): string
}
+/**
+ * build breadcrumbs
+ */
+function breadcrumbs(string $root, string $path): string
+{
+ ob_start();
+
+ $breadcrumbs = explode("/", trim(str_replace($root, "", $path), "/"));
+ echo "<a href=\"$root\">root</a>";
+ $crumb_parts = "";
+ foreach ($breadcrumbs as $idx => $crumb) {
+ $crumb_parts .= "/$crumb";
+ if ($idx < count($breadcrumbs) - 1) {
+ echo "/<a href=\"$root$crumb_parts\">$crumb</a>";
+ } else {
+ echo "/$crumb";
+ }
+ }
+
+ return ob_get_clean();
+}
+
+
+##
+# Output
+##
+
+
$projects_path = realpath($_ENV["PHPGIT_PROJECTS_PATH"]);
$url = parse_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
@@ -251,7 +361,7 @@ if ($url["path"] == "/") {
?><tr><?php
- ?><td><a href="<?php echo $name; ?>/tree"><?php
+ ?><td><a href="/<?php echo uri_encode($name); ?>/tree"><?php
echo $name;
?></a></td><?php
@@ -285,13 +395,7 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
$tree = get_file_tree("$projects_path/$project", "HEAD", "./{$file_path}/");
// show breadcrumbs
- $breadcrumbs = explode("/", $file_path);
- echo "<a href='/$project/tree'>root</a>";
- $crumb_parts = "";
- foreach ($breadcrumbs as $idx => $crumb) {
- $crumb_parts .= "/$crumb";
- echo "/<a href='/$project/tree$crumb_parts'>$crumb</a>";
- }
+ echo breadcrumbs("/$project/tree", "/$project/tree/$file_path");
// build list
?>
@@ -306,7 +410,7 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
<?php
foreach ($tree as $file) {
- $current_file_path = $file_path . "/";
+ $current_file_path = empty($file_path) ? "" : $file_path . "/";
$basename = basename($file["path"]);
?><tr><?php
@@ -314,9 +418,9 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
?><td><?php echo $file["mode"]; ?></td><?php
if ($file["type"] == "blob"):
- ?><td><a href="<?php echo "/$project/blob/$current_file_path$basename"; ?>"><?php echo $basename; ?></a><td><?php
+ ?><td><a href="<?php echo uri_encode("/$project/blob/$current_file_path$basename"); ?>"><?php echo $basename; ?></a><td><?php
else:
- ?><td><a href="<?php echo "/$project/tree/$current_file_path$basename"; ?>"><?php echo $basename; ?></a><td><?php
+ ?><td><a href="<?php echo uri_encode("/$project/tree/$current_file_path$basename"); ?>"><?php echo $basename; ?></a><td><?php
endif;
?></tr><?php
@@ -328,35 +432,49 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
<?php
}
+
// Route: /$project/blob/$file_path
elseif (preg_match("#(.*)/blob/?(.*)#", $url["path"], $matches)) {
$project = urldecode(ltrim($matches[1], "/"));
$file_path = urldecode(rtrim($matches[2], "/"));
-
+
// show breadcrumbs
- $breadcrumbs = explode("/", $file_path);
- echo "<a href='/$project/tree'>root</a>";
- $crumb_parts = "";
- foreach ($breadcrumbs as $idx => $crumb) {
- $crumb_parts .= "/$crumb";
- if ($idx != count($breadcrumbs) - 1) {
- echo "/<a href='/$project/tree$crumb_parts'>$crumb</a>";
- } else {
- echo "/$crumb";
- }
- }
+ echo breadcrumbs("/$project/tree", "/$project/tree/$file_path");
+
+ // get file info
+ $info = get_file_info("$projects_path/$project", $file_path);
+ $contents = read_object_file("$projects_path/$project", $info["name"]);
+ $mime_type = (new finfo(FILEINFO_MIME_TYPE))->buffer($contents);
+
+ $memory_limit = (int)ini_get("memory_limit") * 1024 ** ["k" => 1, "m" => 2, "g" => 3][strtolower(ini_get("memory_limit")[-1])];
?>
- <div class="blob-code-block">
- <pre><code><?php echo file_get_contents("$projects_path/$project/$file_path"); ?></code></pre>
+ <div>
+ Mime Type: <?php echo $mime_type; ?>
+ <br>
+ <?php if (strlen($contents) * 2 < $memory_limit - memory_get_usage()): ?>
+ <?php if (str_starts_with($mime_type, "image/")): ?>
+ <img src="data:image/<?php echo substr($mime_type, 6); ?>;base64,<?php echo base64_encode($contents); ?>">
+ <?php elseif (str_starts_with($mime_type, "audio/")): ?>
+ <audio controls src="data:audio/<?php echo substr($mime_type, 6); ?>;base64,<?php echo base64_encode($contents); ?>" />
+ <?php else: ?>
+ <div class="blob-code-block">
+ <pre><code><?php echo htmlspecialchars($contents); ?></code></pre>
+ </div>
+ <?php endif; ?>
+ <?php else: ?>
+ Can't process. Memory limit of <?php echo ini_get("memory_limit"); ?> would be exhausted.
+ <?php endif; ?>
</div>
<?php
}
+
else {
$path = $projects_path . $url["path"];
var_dump(parse_log($path));
}
+
// display
echo template_root(ob_get_clean());