facebook.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. <?php
  2. class facebook{
  3. const get = 0;
  4. const post = 1;
  5. public function __construct(){
  6. include "lib/nextpage.php";
  7. $this->nextpage = new nextpage("fb");
  8. include "lib/proxy_pool.php";
  9. $this->proxy = new proxy_pool("facebook");
  10. }
  11. public function getfilters($page){
  12. return [
  13. "sort" => [
  14. "display" => "Sort by",
  15. "option" => [
  16. "relevance" => "Relevance",
  17. "most_recent" => "Most recent"
  18. ]
  19. ],
  20. "newer" => [
  21. "display" => "Newer than",
  22. "option" => "_DATE"
  23. ],
  24. "older" => [
  25. "display" => "Older than",
  26. "option" => "_DATE"
  27. ],
  28. "live" => [
  29. "display" => "Livestream",
  30. "option" => [
  31. "no" => "No",
  32. "yes" => "Yes"
  33. ]
  34. ]
  35. ];
  36. }
  37. private function get($url, $get = [], $reqtype = self::get){
  38. $curlproc = curl_init();
  39. if($get !== []){
  40. $get = http_build_query($get);
  41. if($reqtype === self::get){
  42. $headers = [
  43. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0",
  44. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
  45. "Accept-Language: en-US,en;q=0.5",
  46. "Accept-Encoding: gzip",
  47. "DNT: 1",
  48. "Connection: keep-alive",
  49. "Upgrade-Insecure-Requests: 1",
  50. "Sec-Fetch-Dest: document",
  51. "Sec-Fetch-Mode: navigate",
  52. "Sec-Fetch-Site: none",
  53. "Sec-Fetch-User: ?1"
  54. ];
  55. $url .= "?" . $get;
  56. }else{
  57. curl_setopt($curlproc, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  58. $headers = [
  59. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0",
  60. "Accept: */*",
  61. "Accept-Language: en-US,en;q=0.5",
  62. "Accept-Encoding: gzip, deflate, br",
  63. "Content-Type: application/x-www-form-urlencoded",
  64. "X-FB-Friendly-Name: SearchCometResultsPaginatedResultsQuery",
  65. //"X-FB-LSD: AVptQC4a16c",
  66. //"X-ASBD-ID: 129477",
  67. "Content-Length: " . strlen($get),
  68. "Origin: https://www.facebook.com",
  69. "DNT: 1",
  70. "Connection: keep-alive",
  71. "Referer: https://www.facebook.com/watch/",
  72. "Cookie: datr=__GMZCgwVF5BbyvAtfJojQwg; oo=v1%7C3%3A1691641171; wd=955x995",
  73. "Sec-Fetch-Dest: empty",
  74. "Sec-Fetch-Mode: cors",
  75. "Sec-Fetch-Site: same-origin",
  76. "TE: trailers"
  77. ];
  78. curl_setopt($curlproc, CURLOPT_POST, true);
  79. curl_setopt($curlproc, CURLOPT_POSTFIELDS, $get);
  80. }
  81. }
  82. curl_setopt($curlproc, CURLOPT_URL, $url);
  83. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  84. curl_setopt($curlproc, CURLOPT_HTTPHEADER, $headers);
  85. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  86. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  87. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  88. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  89. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  90. $this->proxy->assign_proxy($curlproc);
  91. $data = curl_exec($curlproc);
  92. if(curl_errno($curlproc)){
  93. throw new Exception(curl_error($curlproc));
  94. }
  95. curl_close($curlproc);
  96. return $data;
  97. }
  98. public function video($get){
  99. $search = $get["s"];
  100. $npt = $get["npt"];
  101. $this->out = [
  102. "status" => "ok",
  103. "npt" => null,
  104. "video" => [],
  105. "author" => [],
  106. "livestream" => [],
  107. "playlist" => [],
  108. "reel" => []
  109. ];
  110. if($get["npt"]){
  111. $nextpage =
  112. json_decode(
  113. $this->nextpage->get(
  114. $npt,
  115. "videos"
  116. ),
  117. true
  118. );
  119. // parse next page
  120. $this->video_nextpage($nextpage);
  121. return $this->out;
  122. }
  123. // generate filter data
  124. // {
  125. // "rp_creation_time:0":"{\"name\":\"creation_time\",\"args\":\"{\\\"start_year\\\":\\\"2023\\\",\\\"start_month\\\":\\\"2023-08\\\",\\\"end_year\\\":\\\"2023\\\",\\\"end_month\\\":\\\"2023-08\\\",\\\"start_day\\\":\\\"2023-08-10\\\",\\\"end_day\\\":\\\"2023-08-10\\\"}\"}",
  126. // "videos_sort_by:0":"{\"name\":\"videos_sort_by\",\"args\":\"Most Recent\"}",
  127. // "videos_live:0":"{\"name\":\"videos_live\",\"args\":\"\"}"
  128. // }
  129. $filter = [];
  130. $sort = $get["sort"];
  131. $live = $get["live"];
  132. $older = $get["older"];
  133. $newer = $get["newer"];
  134. if(
  135. $older !== false ||
  136. $newer !== false
  137. ){
  138. if($older === false){
  139. $older = time();
  140. }
  141. if($newer === false){
  142. $newer = 0;
  143. }
  144. $filter["rp_creation_time:0"] =
  145. json_encode(
  146. [
  147. "name" => "creation_time",
  148. "args" =>
  149. json_encode(
  150. [
  151. "start_year" => date("Y", $newer),
  152. "start_month" => date("Y-m", $newer),
  153. "end_year" => date("Y", $older),
  154. "end_month" => date("Y-m", $older),
  155. "start_day" => date("Y-m-d", $newer),
  156. "end_day" => date("Y-m-d", $older)
  157. ]
  158. )
  159. ]
  160. );
  161. }
  162. if($sort != "relevance"){
  163. $filter["videos_sort_by:0"] =
  164. json_encode(
  165. [
  166. "name" => "videos_sort_by",
  167. "args" => "Most Recent"
  168. ]
  169. );
  170. }
  171. if($live != "no"){
  172. $filter["videos_live:0"] = json_encode(
  173. [
  174. "name" => "videos_live",
  175. "args" => ""
  176. ]
  177. );
  178. }
  179. $req = [
  180. "q" => $search
  181. ];
  182. if(count($filter) !== 0){
  183. $req["filters"] =
  184. base64_encode(
  185. json_encode(
  186. $filter
  187. )
  188. );
  189. }
  190. /*
  191. $html =
  192. $this->get(
  193. "https://www.facebook.com/watch/search/",
  194. $req
  195. );*/
  196. $handle = fopen("scraper/facebook.html", "r");
  197. $html = fread($handle, filesize("scraper/facebook.html"));
  198. fclose($handle);
  199. preg_match_all(
  200. '/({"__bbox":.*,"sequence_number":0}})\]\]/',
  201. $html,
  202. $json
  203. );
  204. if(!isset($json[1][1])){
  205. throw new Exception("Could not grep JSON body");
  206. }
  207. $json = json_decode($json[1][1], true);
  208. foreach(
  209. $json
  210. ["__bbox"]
  211. ["result"]
  212. ["data"]
  213. ["serpResponse"]
  214. ["results"]
  215. ["edges"]
  216. as $result
  217. ){
  218. $this->parse_edge($result);
  219. }
  220. // get nextpage data
  221. if(
  222. $json
  223. ["__bbox"]
  224. ["result"]
  225. ["data"]
  226. ["serpResponse"]
  227. ["results"]
  228. ["page_info"]
  229. ["has_next_page"]
  230. == 1
  231. ){
  232. preg_match(
  233. '/handleWithCustomApplyEach\(ScheduledApplyEach,({.*})\);}\);}\);<\/script>/',
  234. $html,
  235. $nextpagedata
  236. );
  237. // [POST] https://www.facebook.com/api/graphql/
  238. // FORM data, not JSON!
  239. $nextpage = [
  240. "av" => "0",
  241. "__user" => null,
  242. "__a" => null,
  243. "__req" => "2",
  244. "__hs" => null,
  245. "dpr" => "1",
  246. "__ccg" => null,
  247. "__rev" => null,
  248. // another client side token
  249. "__s" => $this->randomstring(6) . ":" . $this->randomstring(6) . ":" . $this->randomstring(6),
  250. "__hsi" => null,
  251. // tracking fingerprint (probably generated using webgl)
  252. "__dyn" => "7xeUmwlE7ibwKBWo2vwAxu13w8CewSwMwNw9G2S0im3y4o0B-q1ew65xO2O1Vw8G1Qw5Mx61vw9m1YwBgao6C0Mo5W3S7Udo5q4U2zxe2Gew9O222SUbEaU2eU5O0GpovU19pobodEGdw46wbS1LwTwNwLw8O1pwr86C16w",
  253. "__csr" => $this->randomstring(null),
  254. "__comet_req" => null,
  255. "lsd" => null,
  256. "jazoest" => null,
  257. "__spin_r" => null,
  258. "__spin_b" => null,
  259. "__spin_t" => null,
  260. "fb_api_caller_class" => "RelayModern",
  261. "fb_api_req_friendly_name" => "SearchCometResultsPaginatedResultsQuery",
  262. "variables" => [ // this is json
  263. "UFI2CommentsProvider_commentsKey" => "SearchCometResultsInitialResultsQuery",
  264. "allow_streaming" => false,
  265. "args" => [
  266. "callsite" => "comet:watch_search",
  267. "config" => [
  268. "exact_match" => false,
  269. "high_confidence_config" => null,
  270. "intercept_config" => null,
  271. "sts_disambiguation" => null,
  272. "watch_config" => null
  273. ],
  274. "context" => [
  275. "bsid" => null,
  276. "tsid" => null
  277. ],
  278. "experience" => [
  279. "encoded_server_defined_params" => null,
  280. "fbid" => null,
  281. "type" => "WATCH_TAB_GLOBAL"
  282. ],
  283. "filters" => [],
  284. "text" => $search
  285. ],
  286. "count" => 5,
  287. "cursor" =>
  288. $json
  289. ["__bbox"]
  290. ["result"]
  291. ["data"]
  292. ["serpResponse"]
  293. ["results"]
  294. ["page_info"]
  295. ["end_cursor"],
  296. "displayCommentsContextEnableComment" => false,
  297. "displayCommentsContextIsAdPreview" => false,
  298. "displayCommentsContextIsAggregatedShare" => false,
  299. "displayCommentsContextIsStorySet" => false,
  300. "displayCommentsFeedbackContext" => null,
  301. "feedLocation" => "SEARCH",
  302. "feedbackSource" => 23,
  303. "fetch_filters" => true,
  304. "focusCommentID" => null,
  305. "locale" => null,
  306. "privacySelectorRenderLocation" => "COMET_STREAM",
  307. "renderLocation" => "search_results_page",
  308. "scale" => 1,
  309. "stream_initial_count" => 0,
  310. "useDefaultActor" => false,
  311. "__relay_internal__pv__IsWorkUserrelayprovider" => false,
  312. "__relay_internal__pv__IsMergQAPollsrelayprovider" => false,
  313. "__relay_internal__pv__StoriesArmadilloReplyEnabledrelayprovider" => false,
  314. "__relay_internal__pv__StoriesRingrelayprovider" => false
  315. ],
  316. "server_timestamps" => "true",
  317. "doc_id" => "6761275837251607" // is actually dynamic
  318. ];
  319. // append filters to nextpage
  320. foreach($filter as $key => $value){
  321. $nextpage["variables"]["args"]["filters"][] =
  322. $value;
  323. }
  324. $nextpagedata = json_decode($nextpagedata[1], true);
  325. // get bsid
  326. foreach($nextpagedata["require"] as $key){
  327. foreach($key as $innerkey){
  328. if(is_array($innerkey)){
  329. foreach($innerkey as $inner_innerkey){
  330. if(is_array($inner_innerkey)){
  331. foreach($inner_innerkey as $inner_inner_innerkey){
  332. if(
  333. isset(
  334. $inner_inner_innerkey
  335. ["variables"]
  336. ["args"]
  337. ["context"]
  338. ["bsid"]
  339. )
  340. ){
  341. $nextpage
  342. ["variables"]
  343. ["args"]
  344. ["context"]
  345. ["bsid"] =
  346. $inner_inner_innerkey
  347. ["variables"]
  348. ["args"]
  349. ["context"]
  350. ["bsid"];
  351. }
  352. }
  353. }
  354. }
  355. }
  356. }
  357. }
  358. foreach($nextpagedata["define"] as $key){
  359. if(isset($key[2]["haste_session"])){
  360. $nextpage["__hs"] = $key[2]["haste_session"];
  361. }
  362. if(isset($key[2]["connectionClass"])){
  363. $nextpage["__ccg"] = $key[2]["connectionClass"];
  364. }
  365. if(isset($key[2]["__spin_r"])){
  366. $nextpage["__spin_r"] = (string)$key[2]["__spin_r"];
  367. }
  368. if(isset($key[2]["hsi"])){
  369. $nextpage["__hsi"] = (string)$key[2]["hsi"];
  370. }
  371. if(
  372. isset($key[2]["token"]) &&
  373. !empty($key[2]["token"])
  374. ){
  375. $nextpage["lsd"] = $key[2]["token"];
  376. }
  377. if(isset($key[2]["__spin_r"])){
  378. $nextpage["__spin_r"] = (string)$key[2]["__spin_r"];
  379. $nextpage["__rev"] = $nextpage["__spin_r"];
  380. }
  381. if(isset($key[2]["__spin_b"])){
  382. $nextpage["__spin_b"] = $key[2]["__spin_b"];
  383. }
  384. if(isset($key[2]["__spin_t"])){
  385. $nextpage["__spin_t"] = (string)$key[2]["__spin_t"];
  386. }
  387. }
  388. preg_match(
  389. '/{"u":"\\\\\/ajax\\\\\/qm\\\\\/\?__a=([0-9]+)&__user=([0-9]+)&__comet_req=([0-9]+)&jazoest=([0-9]+)"/',
  390. $html,
  391. $ajaxparams
  392. );
  393. if(count($ajaxparams) !== 5){
  394. throw new Exception("Could not grep the AJAX parameters");
  395. }
  396. $nextpage["__a"] = $ajaxparams[1];
  397. $nextpage["__user"] = $ajaxparams[2];
  398. $nextpage["__comet_req"] = $ajaxparams[3];
  399. $nextpage["jazoest"] = $ajaxparams[4];
  400. /*
  401. $handle = fopen("scraper/facebook-nextpage.json", "r");
  402. $json = fread($handle, filesize("scraper/facebook-nextpage.json"));
  403. fclose($handle);*/
  404. $nextpage["variables"] = json_encode($nextpage["variables"]);
  405. $this->video_nextpage($nextpage);
  406. }
  407. return $this->out;
  408. }
  409. private function video_nextpage($nextpage, $getcursor = false){
  410. $json =
  411. $this->get(
  412. "https://www.facebook.com/api/graphql/",
  413. $nextpage,
  414. self::post
  415. );
  416. $json = json_decode($json, true);
  417. if($json === null){
  418. throw new Exception("Failed to decode next page JSON");
  419. }
  420. foreach(
  421. $json
  422. ["data"]
  423. ["serpResponse"]
  424. ["results"]
  425. ["edges"]
  426. as $result
  427. ){
  428. $this->parse_edge($result);
  429. }
  430. if(
  431. $json
  432. ["data"]
  433. ["serpResponse"]
  434. ["results"]
  435. ["page_info"]
  436. ["has_next_page"] == 1
  437. ){
  438. $nextpage["variables"] = json_decode($nextpage["variables"], true);
  439. $nextpage["variables"]["cursor"] =
  440. $json
  441. ["data"]
  442. ["serpResponse"]
  443. ["results"]
  444. ["page_info"]
  445. ["end_cursor"];
  446. $nextpage["variables"] = json_encode($nextpage["variables"]);
  447. //change this for second call. after, it's static.
  448. // TODO: csr also updates to longer string
  449. $nextpage["__dyn"] = "7xeUmwlEnwn8K2WnFw9-2i5U4e0yoW3q322aew9G2S0zU20xi3y4o0B-q1ew65xOfxO1Vw8G11xmfz81s8hwGwQw9m1YwBgao6C2O0B85W3S7Udo5qfK0EUjwGzE2swwwJK2W2K0zK5o4q0GpovU19pobodEGdw46wbS1LwTwNwLw8O1pwr86C16w";
  450. // TODO: change this on third and 6th call
  451. //$nextpage["__s"] = $this->randomstring(6) . ":" . explode(":", $nextpage["__s"], 2)[1];
  452. $this->out["npt"] = $this->nextpage->store(json_encode($nextpage), "videos");
  453. }
  454. }
  455. private function parse_edge($edge){
  456. $append = "video";
  457. $edge =
  458. $edge
  459. ["relay_rendering_strategy"]
  460. ["view_model"];
  461. if(
  462. strtolower(
  463. $edge
  464. ["video_metadata_model"]
  465. ["video_broadcast_status"]
  466. )
  467. == "live"
  468. ){
  469. // handle livestream
  470. $duration = "_LIVE";
  471. $append = "livestream";
  472. $timetext = null;
  473. $views =
  474. (int)$edge
  475. ["video_metadata_model"]
  476. ["relative_time_string"];
  477. $url_prefix = "https://www.facebook.com/watch/live/?v=";
  478. }elseif(
  479. stripos(
  480. $edge
  481. ["video_metadata_model"]
  482. ["video_broadcast_status"],
  483. "vod"
  484. ) !== false
  485. ){
  486. // handle VOD format
  487. $timetext = null;
  488. $views =
  489. (int)$edge
  490. ["video_metadata_model"]
  491. ["relative_time_string"];
  492. $duration =
  493. $this->hms2int(
  494. $edge
  495. ["video_thumbnail_model"]
  496. ["video_duration_text"]
  497. );
  498. $url_prefix = "https://www.facebook.com/watch/live/?v=";
  499. }else{
  500. // handle normal format
  501. $timetext =
  502. explode(
  503. " · ",
  504. $edge
  505. ["video_metadata_model"]
  506. ["relative_time_string"],
  507. 2
  508. );
  509. if(count($timetext) === 2){
  510. $views = $this->truncatedcount2int($timetext[1]);
  511. }else{
  512. $views = null;
  513. }
  514. $timetext = strtotime($timetext[0]);
  515. $duration =
  516. $this->hms2int(
  517. $edge
  518. ["video_thumbnail_model"]
  519. ["video_duration_text"]
  520. );
  521. $url_prefix = "https://www.facebook.com/watch/?v=";
  522. }
  523. if(
  524. isset(
  525. $edge
  526. ["video_metadata_model"]
  527. ["video_owner_profile"]
  528. ["uri_token"]
  529. )
  530. ){
  531. $profileurl =
  532. "https://www.facebook.com/watch/" .
  533. $edge
  534. ["video_metadata_model"]
  535. ["video_owner_profile"]
  536. ["uri_token"];
  537. }else{
  538. $profileurl =
  539. $edge
  540. ["video_metadata_model"]
  541. ["video_owner_profile"]
  542. ["url"];
  543. }
  544. $this->out[$append][] = [
  545. "title" =>
  546. $this->limitstrlen(
  547. str_replace(
  548. "\n",
  549. " ",
  550. $edge
  551. ["video_metadata_model"]
  552. ["title"]
  553. ),
  554. 100
  555. ),
  556. "description" =>
  557. empty(
  558. $edge
  559. ["video_metadata_model"]
  560. ["save_description"]
  561. ) ?
  562. null :
  563. str_replace(
  564. "\n",
  565. " ",
  566. $this->limitstrlen(
  567. $edge
  568. ["video_metadata_model"]
  569. ["save_description"]
  570. )
  571. ),
  572. "author" => [
  573. "name" =>
  574. $edge
  575. ["video_metadata_model"]
  576. ["video_owner_profile"]
  577. ["name"],
  578. "url" => $profileurl,
  579. "avatar" => null
  580. ],
  581. "date" => $timetext,
  582. "duration" => $duration,
  583. "views" => $views,
  584. "thumb" =>
  585. [
  586. "url" =>
  587. $edge
  588. ["video_thumbnail_model"]
  589. ["thumbnail_image"]
  590. ["uri"],
  591. "ratio" => "16:9"
  592. ],
  593. "url" =>
  594. $url_prefix .
  595. $edge
  596. ["video_click_model"]
  597. ["click_metadata_model"]
  598. ["video_id"]
  599. ];
  600. }
  601. private function randomstring($len){
  602. if($len === null){
  603. $str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-";
  604. $len = rand(141, 145);
  605. $c = 61;
  606. }else{
  607. $str = "abcdefghijklmnopqrstuvwxyz123456789";
  608. $c = 34;
  609. }
  610. $out = null;
  611. for($i=0; $i<$len; $i++){
  612. $out .= $str[rand(0, $c)];
  613. }
  614. return $out;
  615. }
  616. private function limitstrlen($text, $len = 300){
  617. return explode("\n", wordwrap($text, $len, "\n"))[0];
  618. }
  619. private function hms2int($time){
  620. $parts = explode(":", $time, 3);
  621. $time = 0;
  622. if(count($parts) === 3){
  623. // hours
  624. $time = $time + ((int)$parts[0] * 3600);
  625. array_shift($parts);
  626. }
  627. if(count($parts) === 2){
  628. // minutes
  629. $time = $time + ((int)$parts[0] * 60);
  630. array_shift($parts);
  631. }
  632. // seconds
  633. $time = $time + (int)$parts[0];
  634. return $time;
  635. }
  636. private function truncatedcount2int($number){
  637. // decimal should always be 1 number long
  638. $number = explode(" ", $number, 2);
  639. $number = $number[0];
  640. $unit = strtolower($number[strlen($number) - 1]);
  641. $tmp = explode(".", $number, 2);
  642. $number = (int)$number;
  643. if(count($tmp) === 2){
  644. $decimal = (int)$tmp[1];
  645. }else{
  646. $decimal = 0;
  647. }
  648. switch($unit){
  649. case "k":
  650. $exponant = 1000;
  651. break;
  652. case "m":
  653. $exponant = 1000000;
  654. break;
  655. case "b";
  656. $exponant = 1000000000;
  657. break;
  658. default:
  659. $exponant = 1;
  660. break;
  661. }
  662. return ($number * $exponant) + ($decimal * ($exponant / 10));
  663. }
  664. }