X-Git-Url: https://git.cweiske.de/phorkie.git/blobdiff_plain/cdc99846c94bacdd7a2a0681d77bac3de45c4f2a..9a21a1cba3aa4d263d8e541382cb4ba0103fc19a:/src/phorkie/Repository/Post.php diff --git a/src/phorkie/Repository/Post.php b/src/phorkie/Repository/Post.php index 1b60752..a61f2a2 100644 --- a/src/phorkie/Repository/Post.php +++ b/src/phorkie/Repository/Post.php @@ -15,32 +15,56 @@ class Repository_Post * * @return boolean True if the post was successful */ - public function process($postData) + public function process($postData, $sessionData) { if (!isset($postData['files'])) { return false; } + if (!$this->hasContent($postData)) { + return false; + } if (!$this->repo) { $this->repo = $this->createRepo(); } $vc = $this->repo->getVc(); - $this->repo->setDescription($postData['description']); + $bChanged = false; - foreach ($postData['files'] as $arFile) { - if ($arFile['content'] == '' && $arFile['name'] == '') { + $bCommit = false; + if ($postData['description'] != $this->repo->getDescription()) { + $this->repo->setDescription($postData['description']); + $bChanged = true; + } + + foreach ($postData['files'] as $num => $arFile) { + $bUpload = false; + if ($_FILES['files']['error'][$num]['upload'] == 0) { + //valid file upload + $bUpload = true; + } else if ($arFile['content'] == '' && $arFile['name'] == '') { //empty (new) file continue; } - $orignalName = $this->sanitizeFilename($arFile['original_name']); - $name = $this->sanitizeFilename($arFile['name']); + $orignalName = Tools::sanitizeFilename($arFile['original_name']); + $name = Tools::sanitizeFilename($arFile['name']); + + if ($arFile['type'] == '_auto_') { + //FIXME: upload + $arFile['type'] = $this->getType($arFile['content']); + } if ($name == '') { - $name = $this->getNextNumberedFile('phork') - . '.' . $arFile['type']; + if ($bUpload) { + $name = Tools::sanitizeFilename( + $_FILES['files']['name'][$num]['upload'] + ); + } else { + $name = $this->getNextNumberedFile('phork') + . '.' . $arFile['type']; + } } $bNew = false; @@ -48,6 +72,10 @@ class Repository_Post if (!isset($orignalName) || $orignalName == '') { //new file $bNew = true; + if (strpos($name, '.') === false) { + //automatically append file extension if none is there + $name .= '.' . $arFile['type']; + } } else if (!$this->repo->hasFile($orignalName)) { //unknown file //FIXME: Show error message @@ -55,12 +83,17 @@ class Repository_Post } else if (isset($arFile['delete']) && $arFile['delete'] == 1) { $bDelete = true; } else if ($orignalName != $name) { - //FIXME: what to do with overwrites? - $vc->getCommand('mv') - ->addArgument($orignalName) - ->addArgument($name) - ->execute(); - $bChanged = true; + if (strpos($name, '/') === false) { + //ignore names with a slash in it, would be new directory + //FIXME: what to do with overwrites? + $vc->getCommand('mv') + ->addArgument($orignalName) + ->addArgument($name) + ->execute(); + $bCommit = true; + } else { + $name = $orignalName; + } } $file = $this->repo->getFileByName($name, false); @@ -68,39 +101,122 @@ class Repository_Post $command = $vc->getCommand('rm') ->addArgument($file->getFilename()) ->execute(); - $bChanged = true; - } else if ($bNew || $file->getContent() != $arFile['content']) { - file_put_contents($file->getPath(), $arFile['content']); + $bCommit = true; + } else if ($bUpload) { + move_uploaded_file( + $_FILES['files']['tmp_name'][$num]['upload'], + $file->getFullPath() + ); + $command = $vc->getCommand('add') + ->addArgument($file->getFilename()) + ->execute(); + $bCommit = true; + } else if ($bNew + || (isset($arFile['content']) + && $file->getContent() != $arFile['content'] + ) + ) { + $dir = dirname($file->getFullPath()); + if (!is_dir($dir)) { + mkdir($dir, 0777, true); + } + file_put_contents($file->getFullPath(), $arFile['content']); $command = $vc->getCommand('add') ->addArgument($file->getFilename()) ->execute(); - $bChanged = true; + $bCommit = true; } } - if ($bChanged) { + if (isset($sessionData['identity'])) { + $notes = $sessionData['identity']; + } else { + $notes = $sessionData['ipaddr']; + } + + if ($bCommit) { $vc->getCommand('commit') ->setOption('message', '') ->setOption('allow-empty-message') - ->setOption('author', 'Anonymous ') + ->setOption('no-edit') + ->setOption( + 'author', + $sessionData['name'] . ' <' . $sessionData['email'] . '>' + ) ->execute(); + //FIXME: git needs ref BEFORE add + //quick hack until http://pear.php.net/bugs/bug.php?id=19605 is fixed + //also waiting for https://pear.php.net/bugs/bug.php?id=19623 + $vc->getCommand('notes --ref=identity add') + ->setOption('force') + ->setOption('message', "$notes") + ->execute(); + //update info for dumb git HTTP transport + //the post-update hook should do that IMO, but does not somehow + $vc->getCommand('update-server-info')->execute(); + + $bChanged = true; + } + + if ($bChanged) { + //FIXME: index changed files only + //also handle file deletions + $db = new Database(); + $not = new Notificator(); + if ($bNew) { + $db->getIndexer()->addRepo($this->repo); + $not->create($this->repo); + } else { + $commits = $this->repo->getHistory(); + $db->getIndexer()->updateRepo( + $this->repo, + $commits[count($commits)-1]->committerTime, + $commits[0]->committerTime + ); + $not->edit($this->repo); + } } return true; } + protected function hasContent($postData) + { + foreach ($postData['files'] as $num => $arFile) { + if ($_FILES['files']['error'][$num]['upload'] == 0) { + return true; + } + if (isset($arFile['content']) && $arFile['content'] != '') { + return true; + } + if (isset($arFile['name']) && $arFile['name'] != '') { + //binary files do not have content + return true; + } + if (isset($arFile['delete']) && $arFile['delete'] != '') { + //binary files do not have content + return true; + } + } + return false; + } + public function createRepo() { $rs = new Repositories(); $repo = $rs->createNew(); $vc = $repo->getVc(); - $vc->initRepository(); + $vc->getCommand('init') + //this should be setOption, but it fails with a = between name and value + ->addArgument('--separate-git-dir') + ->addArgument( + $GLOBALS['phorkie']['cfg']['gitdir'] . '/' . $repo->id . '.git' + ) + ->addArgument($repo->workDir) + ->execute(); - foreach (glob($repo->repoDir . '/.git/hooks/*') as $hookfile) { - unlink($hookfile); - } - - touch($repo->repoDir . '/.git/git-daemon-export-ok'); + $rs = new Repository_Setup($repo); + $rs->afterInit(); return $repo; } @@ -110,32 +226,42 @@ class Repository_Post $num = -1; do { ++$num; - $files = glob($this->repo->repoDir . '/' . $prefix . $num . '.*'); + $files = glob($this->repo->workDir . '/' . $prefix . $num . '.*'); } while (count($files)); return $prefix . $num; } - /** - * Removes malicious parts from a file name - * - * @param string $file File name from the user - * - * @return string Fixed and probably secure filename - */ - public function sanitizeFilename($file) + public function getType($content, $returnError = false) { - $file = trim($file); - $file = str_replace(array('\\', '//'), '/', $file); - $file = str_replace('/../', '/', $file); - if (substr($file, 0, 3) == '../') { - $file = substr($file, 3); + if (getenv('PATH') == '') { + //php-fpm does not fill $PATH by default + // we have to work around that since System::which() uses it + putenv('PATH=/usr/local/bin:/usr/bin:/bin'); } - if (substr($file, 0, 1) == '../') { - $file = substr($file, 1); + + $tmp = tempnam(sys_get_temp_dir(), 'phorkie-autodetect-'); + file_put_contents($tmp, $content); + $type = Tool_MIME_Type_PlainDetect::autoDetect($tmp); + unlink($tmp); + + if ($returnError && $type instanceof \PEAR_Error) { + return $type; } - return $file; + return $this->findExtForType($type); + } + + protected function findExtForType($type) + { + $ext = 'txt'; + foreach ($GLOBALS['phorkie']['languages'] as $lext => $arLang) { + if ($arLang['mime'] == $type) { + $ext = $lext; + break; + } + } + return $ext; } }