PageRenderTime 24ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/collections/stream.php

https://github.com/agnesrambaud/yacs
PHP | 271 lines | 124 code | 50 blank | 97 comment | 28 complexity | f08f39a9d223fcba50e84f81fbcfdf68 MD5 | raw file
  1. <?php
  2. /**
  3. * stream a file
  4. *
  5. * This script turns a YACS server into a pseudo-streaming server.
  6. * On intranets or at home, with VLC or Winamp or Windows Media Player installed at workstations, it allows people to view films on-demand.
  7. *
  8. * @link http://www.videolan.org/vlc/ VLC media player
  9. *
  10. * This script acts as a redirector for well-known types:
  11. * - [code].aif[/code] (through a [code].m3u[/code] redirector)
  12. * - [code].aiff[/code] (through a [code].m3u[/code] redirector)
  13. * - [code].asf[/code] (through a [code].m3u[/code] redirector)
  14. * - [code].au[/code] (through a [code].m3u[/code] redirector)
  15. * - [code].avi[/code] (through a [code].m3u[/code] redirector)
  16. * - [code].divx[/code] (through a [code].m3u[/code] redirector)
  17. * - [code].mka[/code] (through a [code].m3u[/code] redirector)
  18. * - [code].mkv[/code] (through a [code].m3u[/code] redirector)
  19. * - [code].mov[/code] (through a [code].m3u[/code] redirector)
  20. * - [code].mp3[/code] (through a [code].m3u[/code] redirector)
  21. * - [code].mp4[/code] (through a [code].m3u[/code] redirector)
  22. * - [code].mpe[/code] (through a [code].m3u[/code] redirector)
  23. * - [code].mpeg[/code] (through a [code].m3u[/code] redirector)
  24. * - [code].mpg[/code] (through a [code].m3u[/code] redirector)
  25. * - [code].snd[/code] (through a [code].m3u[/code] redirector)
  26. * - [code].vob[/code] (through a [code].m3u[/code] redirector)
  27. * - [code].wav[/code] (through a [code].m3u[/code] redirector)
  28. * - [code].wma[/code] (through a [code].wax[/code] redirector)
  29. * - [code].wmv[/code] (through a [code].wvx[/code] redirector)
  30. * - [code].ra[/code] (through a [code].ram[/code] redirector)
  31. *
  32. * @link http://www.spartanicus.utvinternet.ie/streaming.htm Streaming audio/video from a web server
  33. * @link http://forums.winamp.com/showthread.php?threadid=65772 The Unofficial M3U and PLS Specification
  34. * @link http://www.panix.com/web/faq/multimedia/streamed.html Streaming Examples
  35. * @link http://www.scriptwell.net/howtoplaysound.htm How To Play Sound
  36. * @link http://empegbbs.com/ubbthreads/showflat.php/Cat/0/Number/63847/Main/63330 How to get Winamp to show id3 info when streaming from the empeg via http
  37. *
  38. * The downloaded object is always cacheable, to avoid IE to remove it too early from temporary directory.
  39. *
  40. * @link http://www.webmasterworld.com/forum88/5891.htm Internet Explorer download problem
  41. *
  42. * For authentication on protected page this script use basic HTTP authentication.
  43. * This means that the anonymous surfer will have either to use the regular login page, or to provide name and password on a per-request basis.
  44. *
  45. * Accept following invocations:
  46. * - stream.php/collection/path/to/file
  47. * - stream.php?file=&lt;collection/path/to/file&gt;
  48. *
  49. * @author Bernard Paques
  50. * @author GnapZ
  51. * @reference
  52. * @license http://www.gnu.org/copyleft/lesser.txt GNU Lesser General Public License
  53. */
  54. // common definitions and initial processing
  55. include_once '../shared/global.php';
  56. include_once 'collections.php';
  57. // check network credentials, if any
  58. if($user = Users::authenticate())
  59. Surfer::empower($user['capability']);
  60. // load the skin -- do it before loading the collection
  61. load_skin('collections');
  62. // the item to browse
  63. $id = NULL;
  64. if(isset($_REQUEST['path']))
  65. $id = urldecode($_REQUEST['path']);
  66. elseif(isset($context['arguments'][1]))
  67. $id = join('/', $context['arguments']);
  68. elseif(isset($context['arguments'][0]))
  69. $id = $context['arguments'][0];
  70. $id = strip_tags($id);
  71. // bind the virtual item to something real
  72. $item = Collections::get($id);
  73. // icons used to depict files and folders
  74. $icons = array();
  75. $icons['folder_icon'] = '<img src="'.$context['url_to_root'].'skins/_reference/files_inline/folder.png" width="13" height="16" alt="" />';
  76. $icons['folder_up_icon'] = '<img src="'.$context['url_to_root'].'skins/_reference/files_inline/folder_up.gif" width="15" height="16" alt="" />';
  77. // the path to this page
  78. $context['path_bar'] = array( 'collections/' => i18n::s('File collections') );
  79. // the collection has to exist
  80. if(!isset($item['collection']) || !$item['collection']) {
  81. Safe::header('Status: 404 Not Found', TRUE, 404);
  82. $context['page_title'] = i18n::s('Unknown collection');
  83. Logger::error(i18n::s('The collection asked for is unknown.'));
  84. // access is prohibited
  85. } elseif((($item['collection_visibility'] == 'N') && !Surfer::is_empowered())
  86. || (($item['collection_visibility'] == 'R') && !Surfer::is_empowered('M'))) {
  87. // give anonymous surfers a chance for HTTP authentication
  88. if(!Surfer::is_logged()) {
  89. Safe::header('WWW-Authenticate: Basic realm="'.utf8::to_iso8859($context['site_name']).'"');
  90. Safe::header('Status: 401 Unauthorized', TRUE, 401);
  91. }
  92. // permission denied to authenticated user
  93. Safe::header('Status: 401 Forbidden', TRUE, 401);
  94. $context['page_title'] = i18n::s('Restricted access');
  95. Logger::error(i18n::s('You are not allowed to perform this operation.'));
  96. // stream this entry
  97. } else {
  98. // bread crumbs to upper levels, if any
  99. $context['path_bar'] = array_merge($context['path_bar'], $item['containers']);
  100. // list where we are
  101. if(isset($item['node_label'])) {
  102. $context['page_title'] = $item['node_label'];
  103. // list parent containers, if any
  104. foreach($item['containers'] as $link => $label) {
  105. $context['prefix'] .= '<a href="'.$link.'">'.$icons['folder_up_icon'].'</a> <a href="'.$link.'">'.$label.'</a>';
  106. }
  107. // houston, we've got a problem
  108. } else
  109. $context['page_title'] = i18n::s('Untitled collection');
  110. // the description is set at the collection index page
  111. if($item['collection_description'])
  112. $context['text'] .= '<p>'.Codes::beautify($item['collection_description'])."</p>\n";
  113. // the prefix on non-index pages
  114. if($item['collection_prefix'])
  115. $context['text'] .= '<p>'.Codes::beautify($item['collection_prefix'])."</p>\n";
  116. // ensure the target file exists
  117. if(!is_readable($item['actual_path']))
  118. $context['text'] .= '<p>'.sprintf(i18n::s('The file %s does not exist. Please check %s.'), $id, Skin::build_link('collections/browse.php?path='.$item['collection'], i18n::s('the index page'), 'shortcut'))."</p>\n";
  119. // build streaming redirector
  120. else {
  121. // depending on the file type
  122. switch($item['node_extension']) {
  123. case 'aif':
  124. case 'aiff':
  125. case 'au':
  126. case 'mka':
  127. case 'mp3':
  128. case 'snd':
  129. case 'wav':
  130. // we are returning a .m3u
  131. $type = 'm3u';
  132. $mime = 'audio/x-mpegurl';
  133. // protect file origin, and set winamp headers
  134. if($context['with_friendly_urls'] == 'Y')
  135. $text = $context['url_to_home'].$context['url_to_root'].'collections/fetch.php/'.rawurlencode($item['collection']).'/'.$item['relative_url'];
  136. else
  137. $text = $context['url_to_home'].$context['url_to_root'].'collections/fetch.php?path='.urlencode($item['id']);
  138. break;
  139. case '3gp':
  140. case 'flv':
  141. case 'm4v':
  142. case 'mov':
  143. case 'mp4':
  144. // we are returning a .m3u
  145. $type = 'm3u';
  146. $mime = 'audio/x-mpegurl';
  147. // where the file actually is
  148. $text = '#EXTM3U'."\n"
  149. .'#EXTINF:-1,'.utf8::to_iso8859(utf8::transcode($item['node_label']))."\n"
  150. .$item['actual_url'];
  151. break;
  152. case 'wma':
  153. // we are returning a .wax
  154. $type = 'wax';
  155. $mime = 'audio/x-ms-wax';
  156. // where the file actually is
  157. $text = '<ASX VERSION="3.0">'."\n"
  158. .' <ENTRY>'."\n"
  159. .' <REF HREF="'.$item['actual_url'].'" />'."\n"
  160. .' </ENTRY>'."\n"
  161. .'</ASX>';
  162. break;
  163. case 'wmv':
  164. // we are returning a .wvx
  165. $type = 'wvx';
  166. $mime = 'video/x-ms-wvx';
  167. // where the file actually is
  168. $text = '<ASX VERSION="3.0">'."\n"
  169. .' <ENTRY>'."\n"
  170. .' <REF HREF="'.$item['actual_url'].'" />'."\n"
  171. .' </ENTRY>'."\n"
  172. .'</ASX>';
  173. break;
  174. case 'ra':
  175. // we are returning a .ram
  176. $type = 'ram';
  177. $mime = 'audio/x-pn-realaudio';
  178. // where the file actually is
  179. $text = $item['actual_url'];
  180. break;
  181. // default
  182. default:
  183. Logger::error(i18n::s('Do not know how to stream this file type.'));
  184. break;
  185. }
  186. //
  187. // transfer to the user agent
  188. //
  189. // if we have a valid redirector
  190. if($mime && $text) {
  191. // no encoding, no compression and no yacs handler...
  192. if(!headers_sent()) {
  193. Safe::header('Content-Type: '.$mime);
  194. Safe::header('Content-Length: '.strlen($text));
  195. }
  196. // suggest a download
  197. if(!headers_sent() && isset($type)) {
  198. $file_name = utf8::to_ascii($id.'.'.$type);
  199. Safe::header('Content-Disposition: attachment; filename="'.$file_name.'"');
  200. }
  201. // enable 30-minute caching (30*60 = 1800), even through https, to help IE6 on download
  202. http::expire(1800);
  203. // strong validator
  204. $etag = '"'.md5($text).'"';
  205. // manage web cache
  206. if(http::validate(NULL, $etag))
  207. return;
  208. // actual transmission except on a HEAD request
  209. if(isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] != 'HEAD'))
  210. echo $text;
  211. // the post-processing hook, then exit
  212. finalize_page(TRUE);
  213. }
  214. }
  215. // the suffix
  216. if($item['collection_suffix'])
  217. $context['text'] .= '<p>'.Codes::beautify($item['collection_suffix'])."</p>\n";
  218. }
  219. // render the skin
  220. render_skin();
  221. ?>