Play images and video from Synology PhotoStation server

path.php 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?
  2. require_once('path.inc.php');
  3. class PathAPI extends WebAPI {
  4. private $isAdmin = false;
  5. private $validIdPrefix = array(
  6. // array( getIDFunction, GetDBObjectFunc, CheckPermission, HasItemFunc, Formula)
  7. 'defaultsmart' => array('GetId', null, null, null, null),
  8. 'smart' => array('GetName', 'SmartAlbum::GetByNames', null, 'SmartHasItem', 'Decorator::SmartFormula'),
  9. 'tag' => array('GetId', 'Label::GetByIds', null, 'TagHasItem', 'Decorator::TagFormula'),
  10. 'album' => array('GetName', 'Album::GetBySharename', 'AlbumAccessible', 'AlbumHasItem', 'Decorator::AlbumFormula'),
  11. 'category' => array('GetId', 'Category::GetByIds', 'CategoryAccessible', 'CategoryHasItem', 'Decorator::CategoryFormula'),
  12. 'photo' => array('GetItemName', 'File::GetPhotoByDBPath', 'ItemAccessible', 'HasNoItem', 'Decorator::PhotoFormula'),
  13. 'video' => array('GetItemName', 'File::GetVideoByDBPath', 'ItemAccessible', 'HasNoItem', 'Decorator::VideoFormula')
  14. );
  15. function __construct() {
  16. parent::__construct(SZ_WEBAPI_API_DESCRIPTION_PATH);
  17. }
  18. protected function Process()
  19. {
  20. if (!strcasecmp($this->method, "getpath")) {
  21. $this->GetPath();
  22. } else if (!strcasecmp($this->method, "checkpath")) {
  23. $this->CheckPath();
  24. }
  25. }
  26. private function GetPath()
  27. {
  28. $param = $this->GetParam_GetPath();
  29. $items = array();
  30. if (!$param) {
  31. $this->SetError(WEBAPI_ERR_BAD_REQUEST);
  32. goto End;
  33. }
  34. $items[] = AlbumAPIUtil::GetRootAlbumInfo($param);
  35. if (0 !== count($param['sharepath'])) {
  36. $result = Album::GetBySharename($param['sharepath']);
  37. $allowComment = AlbumAPIUtil::IsAlbumCommentalbGlobal();
  38. $showAlbumHit = AlbumAPIUtil::IsShowAlbumHit();
  39. $needThumbSize = in_array('thumb_size', $param['additional']);
  40. foreach ($param['sharepath'] as $sharepath) {
  41. $item = array();
  42. $item = Decorator::AlbumFormula($result[$sharepath], array(
  43. 'allowComment' => $allowComment,
  44. 'showAlbumHit' => $showAlbumHit,
  45. 'param' => $param,
  46. 'needThumbSize' => $needThumbSize
  47. ));
  48. $items[] = $item;
  49. }
  50. }
  51. $resp = array(
  52. 'items' => $items,
  53. 'total' => count($items)
  54. );
  55. $this->SetResponse($resp);
  56. End:
  57. return;
  58. }
  59. private function GetParam_GetPath()
  60. {
  61. if (!isset($_REQUEST['id'])){
  62. return false;
  63. }
  64. if (preg_match('/^(photo|video)_/', $_REQUEST['id'])) {
  65. $ids = explode("_", $_REQUEST['id']);
  66. $path = @pack("H*", $ids[1]) .'/'. @pack("H*", $ids[2]);
  67. } else {
  68. $path = $this->DecodeItemId($_REQUEST['id'], '_');
  69. }
  70. if (false === $path) {
  71. return false;
  72. }
  73. $dir = pathinfo($path, PATHINFO_DIRNAME);;
  74. $dirs = array();
  75. while (!in_array($dir, array('.', '', '/'), true)) {
  76. $dirs[] = $dir;
  77. $dir = pathinfo($dir, PATHINFO_DIRNAME);
  78. }
  79. $param = array(
  80. 'additional' => explode(',', $_REQUEST['additional']),
  81. 'sharepath' => array_reverse($dirs),
  82. 'ignore' => explode(',', $_REQUEST['ignore'])
  83. );
  84. return $param;
  85. }
  86. private function CheckPath()
  87. {
  88. $param = $this->GetParam_CheckPath();
  89. if (!$param) {
  90. $this->SetError(WEBAPI_ERR_BAD_REQUEST);
  91. goto End;
  92. }
  93. $allowComment = AlbumAPIUtil::IsAlbumCommentalbGlobal();
  94. $showAlbumHit = AlbumAPIUtil::IsShowAlbumHit();
  95. $needThumbSize = in_array('thumb_size', $param['additional']);
  96. $previous = false;
  97. $items = array();
  98. $formedItem = array();
  99. $last_token = end($param['validToken']);
  100. foreach ($param['validToken'] as $token => $value) {
  101. $type = $value['type'];
  102. $id = $value['id'];
  103. list($idProcessFunc, $GetObjFunc, $permissionFunc, $hasItemFunc, $formula) = $this->validIdPrefix[$type];
  104. if (!$GetObjFunc) {
  105. continue;
  106. }
  107. $id = $this->$idProcessFunc($id);
  108. if (in_array($type, array('photo', 'video'))) {
  109. $objs = call_user_func($GetObjFunc, array($id['dbPath']));
  110. $item = $objs[$id['dbPath']];
  111. } else {
  112. $objs = call_user_func($GetObjFunc, array($id));
  113. $item = $objs[$id];
  114. }
  115. if (!$item) {
  116. $this->SetError(array(PHOTOSTATION_PATH_ACCESS_DENY));
  117. goto End;
  118. }
  119. $items[$token] = array(
  120. 'id' => $token,
  121. 'type' => $type,
  122. 'info' => $item
  123. );
  124. // check current permission
  125. if ($permissionFunc) {
  126. $code = $this->$permissionFunc($item);
  127. if ($type === 'album') {
  128. if ($code === WEBAPI_ERR_NONE && !$previousCode) {
  129. $previousToken = $previousCode = null;
  130. } else if ($last_token != $value && in_array($code, array(PHOTOSTATION_ALBUM_NO_ACCESS_RIGHT, PHOTOSTATION_ALBUM_PASSWORD_ERROR)) && !$previousCode) {
  131. $previousCode = $code;
  132. $previousToken = $token;
  133. // password -> public / private
  134. } else if ($code === PHOTOSTATION_ALBUM_NO_ACCESS_RIGHT && $previousCode === PHOTOSTATION_ALBUM_PASSWORD_ERROR) {
  135. // password -> public
  136. if ($item['public']) {
  137. $this->SetError(array($previousCode, $previousToken));
  138. goto End;
  139. // password -> private
  140. } else {
  141. $this->SetError(array($code, $token));
  142. goto End;
  143. }
  144. // private/password -> password (error)
  145. } else if ($code === PHOTOSTATION_ALBUM_PASSWORD_ERROR &&
  146. in_array($previousCode, array(PHOTOSTATION_ALBUM_NO_ACCESS_RIGHT, PHOTOSTATION_ALBUM_PASSWORD_ERROR))) {
  147. $this->SetError(array($code, $token));
  148. goto End;
  149. // private/password -> password (passed)
  150. } else if ($code == WEBAPI_ERR_NONE && $previousCode && $item['password']) {
  151. $previousCode = $previousToken = null;
  152. // private -> public
  153. } else if ($code == WEBAPI_ERR_NONE && $previousCode && $this->NotPasswordAlbum($item)) {
  154. $this->SetError(array($previousCode, $previousToken));
  155. goto End;
  156. } else if ($code !== WEBAPI_ERR_NONE) {
  157. $this->SetError(array($code, $token));
  158. goto End;
  159. }
  160. } else {
  161. if ($previousCode) {
  162. $this->SetError(array($previousCode, $previousToken));
  163. goto End;
  164. }
  165. if ($code !== WEBAPI_ERR_NONE) {
  166. $this->SetError(array($code, $token));
  167. goto End;
  168. }
  169. }
  170. }
  171. // check previous and current valid
  172. if ($previous) {
  173. $parentObj = $items[$previous];
  174. $parentFunc = $this->validIdPrefix[$parentObj['type']];
  175. // check previous has current
  176. $hasItemFunc = $parentFunc[3];
  177. if ($hasItemFunc && !$this->$hasItemFunc($parentObj['info'], $type, $id, $item)) {
  178. $this->SetError(array(PHOTOSTATION_PATH_ACCESS_DENY));
  179. goto End;
  180. }
  181. }
  182. if ($formula) {
  183. $formedItem[$token] = call_user_func($formula, $item, array(
  184. 'allowComment' => $allowComment,
  185. 'showAlbumHit' => $showAlbumHit,
  186. 'param' => $param,
  187. 'id' => $token,
  188. 'needThumbSize' => $needThumbSize
  189. )
  190. );
  191. } else {
  192. $formedItem[$token] = $items[$token];
  193. }
  194. $previous = $token;
  195. }
  196. $result = array();
  197. foreach ($param['tokens'] as $token) {
  198. if ($formedItem[$token]) {
  199. $result[] = $formedItem[$token];
  200. } else {
  201. $result[] = array(
  202. "id" => $token
  203. );
  204. }
  205. }
  206. $resp['total'] = count($result);
  207. $resp['items'] = $result;
  208. $this->SetResponse($resp);
  209. End:
  210. return;
  211. }
  212. private function ItemAccessible($obj)
  213. {
  214. $relativePath = substr($obj['path'], strlen(SYNOPHOTO_SERVICE_REAL_DIR_PATH));
  215. $dirname = pathinfo($relativePath, PATHINFO_DIRNAME);
  216. $sharename = '.' === $dirname ? '/' : $dirname;
  217. $accessible = csSYNOPhotoMisc::CheckAlbumAccessible($sharename);
  218. return $accessible ? WEBAPI_ERR_NONE : PHOTOSTATION_PHOTO_ACCESS_DENY;
  219. }
  220. private function AlbumAccessible($obj)
  221. {
  222. $sharename = $obj['sharename'];
  223. $accessible = csSYNOPhotoMisc::CheckAlbumAccessible($sharename);
  224. if ($obj['password'] && !$accessible) {
  225. return PHOTOSTATION_ALBUM_PASSWORD_ERROR;
  226. } else if (!$accessible) {
  227. return PHOTOSTATION_ALBUM_NO_ACCESS_RIGHT;
  228. }
  229. return WEBAPI_ERR_NONE;
  230. }
  231. private function CategoryAccessible($obj)
  232. {
  233. if ($obj['hidden'] && !$this->isAdmin) {
  234. return PHOTOSTATION_CATEGORY_ACCESS_DENY;
  235. }
  236. return WEBAPI_ERR_NONE;
  237. }
  238. private function SmartHasItem($parentObj, $itemType, $itemId, $itemObj)
  239. {
  240. $itemlist = SmartAlbum::GetSmartAlbumInstance()->GetItemsInSmartAlbum($parentObj, "filename", "asc", 0, -1);
  241. foreach ($itemlist as $item) {
  242. if ($item['id'] === $itemObj['id']) {
  243. return true;
  244. }
  245. }
  246. return false;
  247. }
  248. private function TagHasItem($parentObj, $itemType, $itemId, $itemObj)
  249. {
  250. if ('photo' === $itemType) {
  251. $item = ItemLabel::GetByItemKeyLabelId($itemObj['id'], $parentObj['id'], true);
  252. } else if ('video' === $itemType) {
  253. $item = ItemLabel::GetByItemKeyLabelId($itemObj['path'], $parentObj['id'], false);
  254. } else {
  255. return false;
  256. }
  257. return $item ? true : false;
  258. }
  259. private function AlbumHasItem($parentObj, $itemType, $itemId, $itemObj)
  260. {
  261. if (in_array($itemType, array('photo', 'video'))) {
  262. return $itemObj['shareid'] === $parentObj['shareid'];
  263. }
  264. return Album::HasItem($parentObj['sharename'], $itemObj['sharename']);
  265. }
  266. private function CategoryHasItem($parentObj, $itemType, $itemId, $itemObj)
  267. {
  268. if ('album' === $itemType) {
  269. return Category::HasItem($parentObj['id'], $itemType, $itemObj['shareid']);
  270. }
  271. return Category::HasItem($parentObj['id'], $itemType, $itemId);
  272. }
  273. private function HasNoItem($parentObj, $itemType, $itemId, $itemObj)
  274. {
  275. return false;
  276. }
  277. private function GetParam_CheckPath()
  278. {
  279. $param = array();
  280. if(!isset($_REQUEST['token'])) {
  281. return false;
  282. }
  283. $tokens = split('/', $_REQUEST['token']);
  284. $validTokens = array();
  285. foreach($tokens as $token) {
  286. $token = trim($token);
  287. if (!$token) {
  288. continue;
  289. }
  290. $parts = explode('_', $token, 2);
  291. if (2 > count($parts) || !array_key_exists($parts[0], $this->validIdPrefix)) {
  292. continue;
  293. }
  294. $validTokens[$token] = array(
  295. 'type' => $parts[0],
  296. 'id' => $parts[1]
  297. );
  298. }
  299. $param = array(
  300. 'tokens' => $tokens,
  301. 'validToken' => $validTokens,
  302. 'ignore' => explode(',', $_REQUEST['ignore']),
  303. 'additional' => explode(',', $_REQUEST['additional'])
  304. );
  305. return $param;
  306. }
  307. private function GetId ($id) {
  308. return $id;
  309. }
  310. private function GetName ($id) {
  311. return @pack('H*', $id);
  312. }
  313. private function GetItemName ($id) {
  314. $parts = split('_', $id);
  315. $sharename = $this->GetName($parts[0]);
  316. $filename = $this->GetName($parts[1]);
  317. return array(
  318. 'sharename' => $sharename,
  319. 'filename' => $filename,
  320. 'dbPath' => SYNOPHOTO_SERVICE_REAL_DIR_PATH. ('/' === $sharename ? '': "$sharename/"). $filename
  321. );
  322. }
  323. private function NotPasswordAlbum ($item) {
  324. return !$item['password'];
  325. }
  326. protected function CheckPermission()
  327. {
  328. $this->isAdmin = isset($_SESSION[SYNOPHOTO_ADMIN_USER]['admin_syno_user']);
  329. return true;
  330. }
  331. }
  332. $api = new PathAPI();
  333. $api->Run();