8cd9323ca1625f082f2dd2e55eb464a22596b4d2
[phorkie.git] / src / phorkie / Repository / Post.php
1 <?php
2 namespace phorkie;
3
4 class Repository_Post
5 {
6     public $repo;
7
8     public function __construct(Repository $repo = null)
9     {
10         $this->repo = $repo;
11     }
12
13     /**
14      * Processes the POST data, changes description and files
15      *
16      * @return boolean True if the post was successful
17      */
18     public function process($postData)
19     {
20         if (!isset($postData['files'])) {
21             return false;
22         }
23
24         if (!$this->repo) {
25             $this->repo = $this->createRepo();
26         }
27
28         $vc = $this->repo->getVc();
29         $this->repo->setDescription($postData['description']);
30
31         $bChanged = false;
32         foreach ($postData['files'] as $num => $arFile) {
33             $bUpload = false;
34             if ($_FILES['files']['error'][$num]['upload'] == 0) {
35                 //valid file upload
36                 $bUpload = true;
37             } else if ($arFile['content'] == '' && $arFile['name'] == '') {
38                 //empty (new) file
39                 continue;
40             }
41
42             $orignalName = $this->sanitizeFilename($arFile['original_name']);
43             $name        = $this->sanitizeFilename($arFile['name']);
44
45             if ($name == '') {
46                 if ($bUpload) {
47                     $name = $this->sanitizeFilename($_FILES['files']['name'][$num]['upload']);
48                 } else {
49                     $name = $this->getNextNumberedFile('phork')
50                         . '.' . $arFile['type'];
51                 }
52             }
53
54             $bNew = false;
55             $bDelete = false;
56             if (!isset($orignalName) || $orignalName == '') {
57                 //new file
58                 $bNew = true;
59                 if (strpos($name, '.') === false) {
60                     //automatically append file extension if none is there
61                     $name .= '.' . $arFile['type'];
62                 }
63             } else if (!$this->repo->hasFile($orignalName)) {
64                 //unknown file
65                 //FIXME: Show error message
66                 continue;
67             } else if (isset($arFile['delete']) && $arFile['delete'] == 1) {
68                 $bDelete = true;
69             } else if ($orignalName != $name) {
70                 //FIXME: what to do with overwrites?
71                 $vc->getCommand('mv')
72                     ->addArgument($orignalName)
73                     ->addArgument($name)
74                     ->execute();
75                 $bChanged = true;
76             }
77
78             $file = $this->repo->getFileByName($name, false);
79             if ($bDelete) {
80                 $command = $vc->getCommand('rm')
81                     ->addArgument($file->getFilename())
82                     ->execute();
83                 $bChanged = true;
84             } else if ($bUpload) {
85                 move_uploaded_file(
86                     $_FILES['files']['tmp_name'][$num]['upload'], $file->getPath()
87                 );
88                 $command = $vc->getCommand('add')
89                     ->addArgument($file->getFilename())
90                     ->execute();
91                 $bChanged = true;
92             } else if ($bNew || $file->getContent() != $arFile['content']) {
93                 file_put_contents($file->getPath(), $arFile['content']);
94                 $command = $vc->getCommand('add')
95                     ->addArgument($file->getFilename())
96                     ->execute();
97                 $bChanged = true;
98             }
99         }
100
101         if ($bChanged) {
102             $vc->getCommand('commit')
103                 ->setOption('message', '')
104                 ->setOption('allow-empty-message')
105                 ->setOption('author', 'Anonymous <anonymous@phorkie>')
106                 ->execute();
107         }
108
109         return true;
110     }
111
112     public function createRepo()
113     {
114         $rs = new Repositories();
115         $repo = $rs->createNew();
116         $vc = $repo->getVc();
117         $vc->initRepository();
118
119         foreach (glob($repo->repoDir . '/.git/hooks/*') as $hookfile) {
120             unlink($hookfile);
121         }
122
123         touch($repo->repoDir . '/.git/git-daemon-export-ok');
124
125         return $repo;
126     }
127
128     public function getNextNumberedFile($prefix)
129     {
130         $num = -1;
131         do {
132             ++$num;
133             $files = glob($this->repo->repoDir . '/' . $prefix . $num . '.*');
134         } while (count($files));
135
136         return $prefix . $num;
137     }
138
139     /**
140      * Removes malicious parts from a file name
141      *
142      * @param string $file File name from the user
143      *
144      * @return string Fixed and probably secure filename
145      */
146     public function sanitizeFilename($file)
147     {
148         $file = trim($file);
149         $file = str_replace(array('\\', '//'), '/', $file);
150         $file = str_replace('/../', '/', $file);
151         if (substr($file, 0, 3) == '../') {
152             $file = substr($file, 3);
153         }
154         if (substr($file, 0, 1) == '../') {
155             $file = substr($file, 1);
156         }
157
158         return $file;
159     }
160 }
161
162 ?>