blobs.php 6.12 KB
Newer Older
Scott committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	Description: Application-level blob-management functions


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

Scott committed
22
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
23
	header('Location: ../../');
Scott committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
	exit;
}


/**
 * Return the URL which will output $blobid from the database when requested, $absolute or relative
 * @param $blobid
 * @param bool $absolute
 * @return mixed|string
 */
function qa_get_blob_url($blobid, $absolute = false)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	return qa_path('blob', array('qa_blobid' => $blobid), $absolute ? qa_opt('site_url') : null, QA_URL_FORMAT_PARAMS);
}


/**
 * Return the full path to the on-disk directory for blob $blobid (subdirectories are named by the first 3 digits of $blobid)
 * @param $blobid
 * @return mixed|string
 */
function qa_get_blob_directory($blobid)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	return rtrim(QA_BLOBS_DIRECTORY, '/') . '/' . substr(str_pad($blobid, 20, '0', STR_PAD_LEFT), 0, 3);
}


/**
 * Return the full page and filename of blob $blobid which is in $format ($format is used as the file name suffix e.g. .jpg)
 * @param $blobid
 * @param $format
 * @return mixed|string
 */
function qa_get_blob_filename($blobid, $format)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	return qa_get_blob_directory($blobid) . '/' . $blobid . '.' . preg_replace('/[^A-Za-z0-9]/', '', $format);
}


/**
 * Create a new blob (storing the content in the database or on disk as appropriate) with $content and $format, returning its blobid.
 * Pass the original name of the file uploaded in $sourcefilename and the $userid, $cookieid and $ip of the user creating it
 * @param $content
 * @param $format
 * @param $sourcefilename
 * @param $userid
 * @param $cookieid
 * @param $ip
 * @return mixed|null|string
 */
function qa_create_blob($content, $format, $sourcefilename = null, $userid = null, $cookieid = null, $ip = null)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	require_once QA_INCLUDE_DIR . 'db/blobs.php';

	$blobid = qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip);

	if (isset($blobid) && defined('QA_BLOBS_DIRECTORY')) {
		// still write content to the database if writing to disk failed
		if (!qa_write_blob_file($blobid, $content, $format))
			qa_db_blob_set_content($blobid, $content);
Scott committed
92 93
	}

Scott committed
94 95
	return $blobid;
}
Scott committed
96 97


Scott committed
98 99 100 101 102 103 104 105 106 107
/**
 * Write the on-disk file for blob $blobid with $content and $format. Returns true if the write succeeded, false otherwise.
 * @param $blobid
 * @param $content
 * @param $format
 * @return bool|mixed
 */
function qa_write_blob_file($blobid, $content, $format)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
108

Scott committed
109
	$written = false;
Scott committed
110

Scott committed
111 112 113
	$directory = qa_get_blob_directory($blobid);
	if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) {
		$filename = qa_get_blob_filename($blobid, $format);
Scott committed
114

Scott committed
115 116 117 118
		$file = fopen($filename, 'xb');
		if (is_resource($file)) {
			if (fwrite($file, $content) >= strlen($content))
				$written = true;
Scott committed
119

Scott committed
120
			fclose($file);
Scott committed
121

Scott committed
122 123
			if (!$written)
				unlink($filename);
Scott committed
124 125 126
		}
	}

Scott committed
127 128
	return $written;
}
Scott committed
129 130


Scott committed
131 132 133 134 135 136 137 138
/**
 * Retrieve blob $blobid from the database, reading the content from disk if appropriate
 * @param $blobid
 * @return array|mixed|null
 */
function qa_read_blob($blobid)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
139

Scott committed
140
	require_once QA_INCLUDE_DIR . 'db/blobs.php';
Scott committed
141

Scott committed
142
	$blob = qa_db_blob_read($blobid);
Scott committed
143

Scott committed
144 145
	if (isset($blob) && defined('QA_BLOBS_DIRECTORY') && !isset($blob['content']))
		$blob['content'] = qa_read_blob_file($blobid, $blob['format']);
Scott committed
146

Scott committed
147 148
	return $blob;
}
Scott committed
149 150


Scott committed
151 152 153 154 155 156 157 158 159
/**
 * Read the content of blob $blobid in $format from disk. On failure, it will return false.
 * @param $blobid
 * @param $format
 * @return mixed|null|string
 */
function qa_read_blob_file($blobid, $format)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
160

Scott committed
161 162 163 164 165 166
	$filename = qa_get_blob_filename($blobid, $format);
	if (is_readable($filename))
		return file_get_contents($filename);
	else
		return null;
}
Scott committed
167 168


Scott committed
169 170 171 172 173 174 175 176
/**
 * Delete blob $blobid from the database, and remove the on-disk file if appropriate
 * @param $blobid
 * @return mixed
 */
function qa_delete_blob($blobid)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
177

Scott committed
178
	require_once QA_INCLUDE_DIR . 'db/blobs.php';
Scott committed
179

Scott committed
180 181
	if (defined('QA_BLOBS_DIRECTORY')) {
		$blob = qa_db_blob_read($blobid);
Scott committed
182

Scott committed
183 184
		if (isset($blob) && !isset($blob['content']))
			unlink(qa_get_blob_filename($blobid, $blob['format']));
Scott committed
185 186
	}

Scott committed
187 188
	qa_db_blob_delete($blobid);
}
Scott committed
189 190


Scott committed
191 192 193 194 195 196 197 198 199
/**
 * Delete the on-disk file for blob $blobid in $format
 * @param $blobid
 * @param $format
 * @return mixed
 */
function qa_delete_blob_file($blobid, $format)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
200

Scott committed
201 202
	unlink(qa_get_blob_filename($blobid, $format));
}
Scott committed
203 204


Scott committed
205 206 207 208 209 210 211 212
/**
 * Check if blob $blobid exists
 * @param $blobid
 * @return bool|mixed
 */
function qa_blob_exists($blobid)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
213

Scott committed
214
	require_once QA_INCLUDE_DIR . 'db/blobs.php';
Scott committed
215

Scott committed
216 217
	return qa_db_blob_exists($blobid);
}