├── README.md ├── data └── .gitignore ├── get.php └── send.php /README.md: -------------------------------------------------------------------------------- 1 | # gammu-php 2 | 3 | A php API that enables you to send and receive SMS via a simple REST API 4 | 5 | Find more about how to use it here: 6 | 7 | https://blog.haschek.at/2021/raspberry-pi-sms-gateway.html 8 | === 9 | 10 | # Prerequisites 11 | - A USB modem dongle you can put into modem mode 12 | - gammu and gammu-smsd 13 | - php and php-json 14 | 15 | From within the directory where the two php files (`send.php` and `get.php`) are stored, run `php -S 0.0.0.0:8080` which will serve the two files to anyone on the network on port 8080. 16 | 17 | ## Sending SMS 18 | 19 | Just call `http://ip.of.your.pi/send.php?phone=07921XXXXXX&text=Testmessage` from curl or a browser and it will return a JSON object indicating if it failed (status:error), or succeeded (status:ok) 20 | 21 | The variables `phone` and `text` are mandator and can be sent via GET or POST (both POST variable or JSON body supported) 22 | 23 | ```json 24 | { 25 | "status": "ok", 26 | "log": "2021-12-04 15:43:39\ngammu-smsd-inject TEXT 07921XXXXXX -unicode -text 'Testmessage'\ngammu-smsd-inject[2669]: Warning: No PIN code in /etc/gammu-smsdrc file\ngammu-smsd-inject[2669]: Created outbox message OUTC20211204_164340_00_07921XXXXXX_sms0.smsbackup\nWritten message with ID /var/spool/gammu/outbox/OUTC20211204_164340_00_07921XXXXXX_sms0.smsbackup\n\n\n" 27 | } 28 | ``` 29 | 30 | ### Receiving SMS with the API 31 | 32 | Call `http://ip.of.your.pi:8080/get.php` 33 | 34 | And it will return you all messages also in a JSON object 35 | 36 | ```json 37 | curl -s http://ip.of.your.pi:8080/get.php 38 | [ 39 | { 40 | "id": "f0a7789a657bb34e43c17c8e64609c48", 41 | "timestamp": 1638636342, 42 | "year": "2021", 43 | "month": "12", 44 | "day": "04", 45 | "time": "16:45", 46 | "test": "04.12.2021 16:45:42", 47 | "sender": "+437921XXXXXX", 48 | "message": "Hello bob!" 49 | }, 50 | { 51 | "id": "c358d0a4e5868c1d7d2eedab181eddd6", 52 | "timestamp": 1638636414, 53 | "year": "2021", 54 | "month": "12", 55 | "day": "04", 56 | "time": "16:46", 57 | "test": "04.12.2021 16:46:54", 58 | "sender": "+437921XXXXXX", 59 | "message": "Hello " 60 | } 61 | ] 62 | ``` -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /get.php: -------------------------------------------------------------------------------- 1 | $file) 17 | { 18 | $p = explode('_',trim($file)); 19 | 20 | //since MMS will have the .bin file extension, let's skip them 21 | if(!endsWith($file,'txt')) continue; 22 | 23 | //unique id 24 | $id = hash('md5',$file); 25 | 26 | //time parsing 27 | $datetime = substr($p[0],2); 28 | $year = intval(substr($datetime,0,4)); 29 | $month = intval(substr($datetime,4,2)); 30 | $day = intval(substr($datetime,6,2)); 31 | $hour = intval(substr($p[1],0,2)); 32 | $min = intval(substr($p[1],2,2)); 33 | $sec = intval(substr($p[1],4,2)); 34 | 35 | //message stuff 36 | $message = file_get_contents(DATADIR.'/'.$file); 37 | $sender = $p[3]; 38 | $part = intval($p[4]); 39 | 40 | // we only care if it's the first part of a message. 41 | // the other parts will be handled separately 42 | if($part==0) 43 | { 44 | $otherparts = findParts($files,$sender,$index); 45 | if($otherparts) 46 | $message.=$otherparts; 47 | } 48 | else continue; 49 | 50 | //just cutting off any white spaces 51 | $message = trim($message); 52 | 53 | //what we're going to return in the API 54 | $data[] = [ 55 | 'id'=>$id, 56 | 'timestamp' => strtotime("$day-$month-$year $hour:$min:$sec"), 57 | 'year'=>$year,'month'=>$month,'day'=>$day, 58 | 'time'=>"$hour:$min", 59 | 'sender'=>$sender, 60 | 'message'=>$message 61 | ]; 62 | 63 | } 64 | 65 | header('Content-Type: application/json; charset=utf-8'); 66 | 67 | echo json_encode($data); 68 | 69 | 70 | 71 | //some functions that will make our lives easier 72 | 73 | function findParts($files,$targetsender,$greaterthanindex) 74 | { 75 | $lastpart = 0; 76 | $messageparts = []; 77 | foreach($files as $index => $file) 78 | { 79 | if($index <= $greaterthanindex) continue; 80 | $p = explode('_',trim($file)); 81 | $sender = $p[3]; 82 | $part = intval($p[4]); 83 | 84 | //could be a mixed-in message, so no need to end the function here 85 | if($sender != $targetsender) continue; 86 | 87 | //if it's a part zero again, it's a new message 88 | if($part==0) break; 89 | 90 | //if we find another part from the target number, it's obviously over 91 | if($part <= $lastpart) break; 92 | else 93 | $messageparts[] = file_get_contents(DATADIR.'/'.$file); 94 | 95 | $lastpart = $part; 96 | } 97 | 98 | if(count($messageparts)>=1) return implode("",$messageparts); 99 | else return false; 100 | } 101 | 102 | function startsWith( $haystack, $needle ) { 103 | $length = strlen( $needle ); 104 | return substr( $haystack, 0, $length ) === $needle; 105 | } 106 | function endsWith( $haystack, $needle ) { 107 | $length = strlen( $needle ); 108 | if( !$length ) { 109 | return true; 110 | } 111 | return substr( $haystack, -$length ) === $needle; 112 | } 113 | -------------------------------------------------------------------------------- /send.php: -------------------------------------------------------------------------------- 1 | \"\"\n"); 7 | $text = $argv[2]; 8 | $rec = filter_var($argv[1], FILTER_SANITIZE_NUMBER_INT); 9 | } else { 10 | $text = trim($_REQUEST['text']); 11 | $rec = filter_var($_REQUEST['phone'], FILTER_SANITIZE_NUMBER_INT); 12 | 13 | if(!$text && !$rec) 14 | { 15 | $inputJSON = file_get_contents('php://input'); 16 | $input = json_decode($inputJSON, TRUE); //convert JSON into array 17 | $text = $input['text']; 18 | $rec = filter_var($input['phone'], FILTER_SANITIZE_NUMBER_INT); 19 | } 20 | 21 | if (!$text || !$rec) 22 | exit(json_encode(['status' => 'err', 'reason' => 'Phone number and text required'])); 23 | } 24 | 25 | 26 | ob_start(); 27 | $cmd = sprintf('gammu-smsd-inject TEXT %s -unicode -len '.(strlen($text)+1).' -text %s', $rec, escapeshellarg($text)); 28 | $log .= $cmd . PHP_EOL; 29 | $log .= shell_exec($cmd) . PHP_EOL . PHP_EOL; 30 | file_put_contents($file, $log, FILE_APPEND | LOCK_EX); 31 | echo $log; 32 | $cont= ob_get_contents(); 33 | ob_end_clean(); 34 | 35 | header('Content-Type: application/json; charset=utf-8'); 36 | 37 | exit(json_encode(['status' => 'ok', 'log' => $log])); 38 | --------------------------------------------------------------------------------