Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
/**
5
 * Write the files as a TAR archive
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
22
 *
23
 * @category   File Formats
24
 * @package    File_Archive
25
 * @author     Vincent Lascaux <vincentlascaux@php.net>
26
 * @copyright  1997-2005 The PHP Group
27
 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL
28
 * @version    CVS: $Id: Tar.php,v 1.20 2008/06/05 21:30:47 cbrunet Exp $
29
 * @link       http://pear.php.net/package/File_Archive
30
 */
31
 
32
require_once "File/Archive/Writer/Archive.php";
33
 
34
/**
35
 * Write the files as a TAR archive
36
 */
37
class File_Archive_Writer_Tar extends File_Archive_Writer_Archive
38
{
39
    var $buffer;
40
    var $useBuffer;
41
 
42
    var $filename = null;
43
    var $stats = null;
44
 
45
 
46
    /**
47
     * Creates the TAR header for a file
48
     *
49
     * @param string $filename name of the file
50
     * @param array $stat statistics of the file
51
     * @return string A 512 byte header for the file
52
     * @access private
53
     */
54
    function tarHeader($filename, $stat)
55
    {
56
        $mode = isset($stat[2]) ? $stat[2] : 0x8000;
57
        $uid  = isset($stat[4]) ? $stat[4] : 0;
58
        $gid  = isset($stat[5]) ? $stat[5] : 0;
59
        $size = $stat[7];
60
        $time = isset($stat[9]) ? $stat[9] : time();
61
        $link = "";
62
 
63
        if ($mode & 0x4000) {
64
            $type = 5;        // Directory
65
        } else if ($mode & 0x8000) {
66
            $type = 0;        // Regular
67
        } else if ($mode & 0xA000) {
68
            $type = 1;        // Link
69
            $link = @readlink($current);
70
        } else {
71
            $type = 9;        // Unknown
72
        }
73
 
74
        $filePrefix = '';
75
        if (strlen($filename) > 255) {
76
            return PEAR::raiseError(
77
                "$filename is too long to be put in a tar archive"
78
            );
79
        } else if (strlen($filename) > 100) {
80
            // need a path component of max 155 bytes
81
            $pos = strrpos(substr($filename, 0, 155), '/');
82
            if(strlen($filename) - $pos > 100) {
83
                // filename-component may not exceed 100 bytes
84
                return PEAR::raiseError(
85
                        "$filename is too long to be put in a tar archive");
86
            }
87
            $filePrefix = substr($filename, 0, $pos);
88
            $filename = substr($filename, $pos+1);
89
        }
90
 
91
        $blockbeg = pack("a100a8a8a8a12a12",
92
            $filename,
93
            decoct($mode),
94
            sprintf("%6s ",decoct($uid)),
95
            sprintf("%6s ",decoct($gid)),
96
            sprintf("%11s ",decoct($size)),
97
            sprintf("%11s ",decoct($time))
98
            );
99
 
100
        $blockend = pack("a1a100a6a2a32a32a8a8a155a12",
101
            $type,
102
            $link,
103
            "ustar",
104
            "00",
105
            "Unknown",
106
            "Unknown",
107
            "",
108
            "",
109
            $filePrefix,
110
            "");
111
 
112
        $checksum = 8*ord(" ");
113
        for ($i = 0; $i < 148; $i++) {
114
            $checksum += ord($blockbeg{$i});
115
        }
116
        for ($i = 0; $i < 356; $i++) {
117
            $checksum += ord($blockend{$i});
118
        }
119
 
120
        $checksum = pack("a8",sprintf("%6s ",decoct($checksum)));
121
 
122
        return $blockbeg . $checksum . $blockend;
123
    }
124
    /**
125
     * Creates the TAR footer for a file
126
     *
127
     * @param  int $size the size of the data that has been written to the TAR
128
     * @return string A string made of less than 512 characteres to fill the
129
     *         last 512 byte long block
130
     * @access private
131
     */
132
    function tarFooter($size)
133
    {
134
        if ($size % 512 > 0) {
135
            return pack("a".(512 - $size%512), "");
136
        } else {
137
            return "";
138
        }
139
    }
140
 
141
    function flush()
142
    {
143
        if ($this->filename !== null) {
144
            if ($this->useBuffer) {
145
                $this->stats[7] = strlen($this->buffer);
146
 
147
                $header = $this->tarHeader($this->filename, $this->stats);
148
                if (PEAR::isError($header)) {
149
                    return $header;
150
                }
151
                $this->innerWriter->writeData($header);
152
                $this->innerWriter->writeData(
153
                    $this->buffer
154
                );
155
            }
156
            $this->innerWriter->writeData(
157
                $this->tarFooter($this->stats[7])
158
            );
159
        }
160
        $this->buffer = "";
161
    }
162
 
163
    function _newFile($filename, $stats = array(),
164
                     $mime = "application/octet-stream")
165
    {
166
        $err = $this->flush();
167
        if (PEAR::isError($err)) {
168
            return $err;
169
        }
170
 
171
        $this->useBuffer = !isset($stats[7]);
172
        $this->filename = $filename;
173
        $this->stats = $stats;
174
 
175
        if (!$this->useBuffer) {
176
            $header = $this->tarHeader($filename, $stats);
177
            if (PEAR::isError($header)) {
178
                return $header;
179
            }
180
            return $this->innerWriter->writeData($header);
181
        }
182
    }
183
 
184
    /**
185
     * @see File_Archive_Writer::close()
186
     */
187
    function close()
188
    {
189
        $err = $this->flush();
190
        if (PEAR::isError($err)) {
191
            return $err;
192
        }
193
        $this->innerWriter->writeData(pack("a1024", ""));
194
        parent::close();
195
    }
196
    /**
197
     * @see File_Archive_Writer::writeData()
198
     */
199
    function writeData($data)
200
    {
201
        if ($this->useBuffer) {
202
            $this->buffer .= $data;
203
        } else {
204
            $this->innerWriter->writeData($data);
205
        }
206
 
207
    }
208
    /**
209
     * @see File_Archive_Writer::writeFile()
210
     */
211
    function writeFile($filename)
212
    {
213
        if ($this->useBuffer) {
214
            if (!file_exists($filename)) {
215
                return PEAR::raiseError("File not found: $filename.");
216
            }
217
            $this->buffer .= file_get_contents($filename);
218
        } else {
219
            $this->innerWriter->writeFile($filename);
220
        }
221
    }
222
    /**
223
     * @see File_Archive_Writer::getMime()
224
     */
225
    function getMime() { return "application/x-tar"; }
226
}
227
 
228
 
229
/**
230
 * A tar archive cannot contain files with name of folders longer than 255 chars
231
 * This filter removes them
232
 *
233
 * @see File_Archive_Predicate, File_Archive_Reader_Filter
234
 */
235
require_once "File/Archive/Predicate.php";
236
class File_Archive_Predicate_TARCompatible extends File_Archive_Predicate
237
{
238
    function isTrue($source)
239
    {
240
        return strlen($source->getFilename()) <= 255;
241
    }
242
}
243
 
244
?>