Skip to content

Commit 041088b

Browse files
authored
Merge pull request #1 from walid-khalafi/feature/config-security-and-core-refactor
Feature/config security and core refactor
2 parents 01c9c34 + 872ac70 commit 041088b

3 files changed

Lines changed: 246 additions & 100 deletions

File tree

.htaccess

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
1+
# ---------------------------------------------------------
2+
# Enable Apache mod_rewrite for clean and dynamic URL handling
3+
# ---------------------------------------------------------
14
RewriteEngine On
5+
6+
# ---------------------------------------------------------
7+
# Define the base URL path for the rewrite rules
8+
# Adjust this if the project is in a subfolder (e.g., /myapp/)
9+
# ---------------------------------------------------------
210
RewriteBase /
11+
12+
# ---------------------------------------------------------
13+
# Prevent rewriting the index.php file itself
14+
# This ensures direct access to index.php remains unchanged
15+
# ---------------------------------------------------------
316
RewriteRule ^index\.php$ - [L]
17+
18+
# ---------------------------------------------------------
19+
# Condition: Requested resource does NOT match an existing file
20+
# ---------------------------------------------------------
421
RewriteCond %{REQUEST_FILENAME} !-f
22+
23+
# ---------------------------------------------------------
24+
# Condition: Requested resource does NOT match an existing directory
25+
# ---------------------------------------------------------
526
RewriteCond %{REQUEST_FILENAME} !-d
27+
28+
# ---------------------------------------------------------
29+
# Redirect all other requests to index.php
30+
# This allows a single PHP entry point to handle routing
31+
# ---------------------------------------------------------
632
RewriteRule . /index.php [L]
33+
34+
# =========================================================
35+
# Additional Security Headers (Optional but Recommended)
36+
# =========================================================
37+
38+
# Prevent MIME type sniffing by browsers
39+
Header set X-Content-Type-Options "nosniff"
40+
41+
# Disallow embedding the site in iframes to prevent clickjacking
42+
Header set X-Frame-Options "DENY"
43+
44+
# Enforce secure HTTP Referrer Policy
45+
Header always set Referrer-Policy "no-referrer-when-downgrade"
46+
47+
# Mitigate some cross-site scripting (XSS) attacks
48+
Header set X-XSS-Protection "1; mode=block"

README.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,53 @@
1-
# TelegramRobotsProxy
1+
# 🤖 Telegram Robots Proxy
22

3-
this Script retranslates queries to telegram bot API
3+
A lightweight PHP script that acts as a **proxy layer** between your client application and the official **Telegram Bot API**.
4+
It receives incoming requests, processes them, and forwards them to the Telegram servers — useful for adding custom logging, security layers, or bypassing access restrictions.
5+
6+
---
7+
8+
## ✨ Features
9+
- **Proxy functionality** for Telegram Bot API requests
10+
- Easy to deploy on any server with PHP & Apache
11+
- Supports clean URLs via `.htaccess` rewrite rules
12+
- BSD-3-Clause licensed for flexible use
13+
14+
---
15+
16+
## 📂 Project Structure
17+
├── index.php # Core proxy script
18+
├── .htaccess # URL rewrite and security headers
19+
├── LICENSE # BSD-3-Clause license
20+
└── README.md # Project documentation
21+
22+
23+
## 🚀 Getting Started
24+
25+
### 1. Requirements
26+
- PHP 7.4+
27+
- Apache with `mod_rewrite` enabled
28+
### 2. Installation
29+
Clone the repository into your web server's root:
30+
```bash
31+
git clone https://github.com/walid-khalafi/TelegramRobotsProxy.git
32+
cd TelegramRobotsProxy
33+
34+
35+
### 3. Configuration
36+
Edit config.php (create if not present) to set:
37+
- Your Telegram Bot Token
38+
- Telegram API endpoint
39+
- Optional: IP whitelist or API Key
40+
41+
42+
### 4. Deployment
43+
Upload the project to your hosting environment and ensure .htaccess is active.
44+
45+
46+
# 🛡 Security Recommendations
47+
- Restrict access by IP or authentication
48+
- Enable HTTPS on your server
49+
- Log requests and mask sensitive data
50+
51+
52+
#💡 Contributing
53+
Contributions are welcome! Fork the repository, make your changes in a feature branch, and submit a Pull Request.

index.php

Lines changed: 152 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,157 @@
1-
<?php
1+
<?php
22
/**
3-
* Script retranslates queries to telegram bot API
3+
* Telegram API Proxy
4+
* -------------------
5+
* Acts as a middle layer between the client and Telegram Bot API.
6+
* Intercepts incoming HTTP requests and forwards them to the Telegram servers,
7+
* optionally logging request/response details for debugging or analytics.
48
*/
9+
510
class TelegramApiProxy {
6-
private $url;
7-
private $ch;
8-
private $log = false;
9-
10-
public function __construct(){
11-
$this->getUrl();
12-
$this->initCurl();
13-
}
14-
15-
public function setLog(bool $log){
16-
$this->log = $log;
17-
}
18-
19-
private function log(string $m){
20-
if(!$this->log) return;
21-
file_put_contents('proxy.log', $m . PHP_EOL, FILE_APPEND);
22-
}
23-
24-
public function start(){
25-
$this->log('[' . date('Y-m-d H:i:s') . '] Query init. URL: ' . $this->url);
26-
$this->sendRequest();
27-
28-
$response = curl_exec($this->ch);
29-
$debug = curl_getinfo($this->ch);
30-
$this->log('Response headers: code=' . $debug['http_code'] . '; content_type=' . $debug['content_type'] . '; size_upload=' . $debug['size_upload'] . '; size_download=' . $debug['size_upload'] . ';');
31-
$this->log('Response body: ' . $response);
32-
$this->log(' ');
33-
34-
$this->sendResponse($response, $debug['content_type'], $debug['http_code']);
35-
}
36-
37-
private function sendResponse(string $response, string $type, int $code){
38-
header('Content-type: ' . $type, $code);
39-
die($response);
40-
}
41-
42-
public function getUrl(){
43-
$dir = dirname($_SERVER['SCRIPT_NAME']); // detect path to dir
44-
if(strpos($_SERVER['REQUEST_URI'], $dir) === 0){
45-
$uri = substr($_SERVER['REQUEST_URI'], strlen($dir));
46-
} else {
47-
$uri = $_SERVER['REQUEST_URI'];
48-
}
49-
50-
if(substr($uri, 0, 1) != '/'){
51-
$uri = '/' . $uri;
52-
}
53-
54-
return $this->url = "https://api.telegram.org" . $uri;
55-
}
56-
57-
private function initCurl(){
58-
$this->ch = curl_init($this->url);
59-
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
60-
return $this->ch;
61-
}
62-
63-
private function sendRequest(){
64-
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
65-
$method = 'GET';
66-
67-
$this->log('HTTP Request: ' . $method);
68-
69-
$this->log('HTTP Request2: ' . file_get_contents('php://input'));
70-
71-
if($method == 'POST' || file_get_contents('php://input')!='' || sizeof($_POST)>0){
72-
curl_setopt($this->ch, CURLOPT_POST, true);
73-
74-
if(sizeof($_FILES) > 0){
75-
$post = [];
76-
foreach ($_FILES as $name => $file) {
77-
$post[$name] = new CURLFile($file['tmp_name'], $file['type'], $file['name']);
78-
}
79-
80-
foreach ($_POST as $name => $value) {
81-
$post[$name] = $value;
82-
}
83-
84-
} else {
85-
$post = file_get_contents('php://input');
86-
$ct = $_SERVER['HTTP_CONTENT_TYPE'] ?? $_SERVER['CONTENT_TYPE'];
87-
curl_setopt($this->ch, CURLOPT_HTTPHEADER, ['Content-type: ' . $ct]);
88-
}
89-
90-
$this->log('Send To Telegram HTTP Request body: ' . json_encode($post,JSON_UNESCAPED_UNICODE ));
91-
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
92-
$this->log('Send data: ' . var_export($post, true));
93-
94-
} else {
95-
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $method);
96-
}
97-
}
11+
/** @var string Fully qualified API request URL */
12+
private $url;
13+
14+
/** @var resource cURL handler */
15+
private $ch;
16+
17+
/** @var bool Enable/disable request logging */
18+
private $log = false;
19+
20+
/**
21+
* Constructor:
22+
* - Detects target URL
23+
* - Initializes cURL session
24+
*/
25+
public function __construct() {
26+
$this->getUrl();
27+
$this->initCurl();
28+
}
29+
30+
/**
31+
* Enable or disable logging.
32+
* @param bool $log
33+
*/
34+
public function setLog(bool $log) {
35+
$this->log = $log;
36+
}
37+
38+
/**
39+
* Append message to log file if logging is enabled.
40+
* @param string $m
41+
*/
42+
private function log(string $m) {
43+
if (!$this->log) return;
44+
file_put_contents('proxy.log', $m . PHP_EOL, FILE_APPEND);
45+
}
46+
47+
/**
48+
* Main request handler:
49+
* - Logs initialization
50+
* - Prepares and sends the request
51+
* - Handles the response
52+
*/
53+
public function start() {
54+
$this->log('[' . date('Y-m-d H:i:s') . '] Query init. URL: ' . $this->url);
55+
$this->sendRequest();
56+
57+
$response = curl_exec($this->ch);
58+
$debug = curl_getinfo($this->ch);
59+
60+
$this->log(sprintf(
61+
'Response headers: code=%d; content_type=%s; size_upload=%d; size_download=%d;',
62+
$debug['http_code'] ?? 0,
63+
$debug['content_type'] ?? '',
64+
$debug['size_upload'] ?? 0,
65+
$debug['size_download'] ?? 0
66+
));
67+
68+
$this->log('Response body: ' . $response);
69+
$this->log(str_repeat('-', 50));
70+
71+
$this->sendResponse($response, $debug['content_type'] ?? 'application/json', $debug['http_code'] ?? 200);
72+
}
73+
74+
/**
75+
* Send the HTTP response back to client with correct headers.
76+
* @param string $response
77+
* @param string $type
78+
* @param int $code
79+
*/
80+
private function sendResponse(string $response, string $type, int $code) {
81+
http_response_code($code);
82+
header('Content-Type: ' . $type);
83+
echo $response;
84+
exit;
85+
}
86+
87+
/**
88+
* Construct full Telegram API URL based on incoming request URI.
89+
* @return string
90+
*/
91+
public function getUrl() {
92+
$dir = dirname($_SERVER['SCRIPT_NAME']); // Detect script directory
93+
if (strpos($_SERVER['REQUEST_URI'], $dir) === 0) {
94+
$uri = substr($_SERVER['REQUEST_URI'], strlen($dir));
95+
} else {
96+
$uri = $_SERVER['REQUEST_URI'];
97+
}
98+
99+
if (substr($uri, 0, 1) !== '/') {
100+
$uri = '/' . $uri;
101+
}
102+
103+
return $this->url = "https://api.telegram.org" . $uri;
104+
}
105+
106+
/**
107+
* Initialize cURL session for the prepared URL.
108+
* @return resource
109+
*/
110+
private function initCurl() {
111+
$this->ch = curl_init($this->url);
112+
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
113+
return $this->ch;
114+
}
115+
116+
/**
117+
* Prepare and send the HTTP request to Telegram API.
118+
*/
119+
private function sendRequest() {
120+
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
121+
$this->log('HTTP Request: ' . $method);
122+
$rawInput = file_get_contents('php://input');
123+
$this->log('HTTP Raw Input: ' . $rawInput);
124+
125+
if ($method === 'POST' || $rawInput !== '' || !empty($_POST)) {
126+
curl_setopt($this->ch, CURLOPT_POST, true);
127+
128+
if (!empty($_FILES)) {
129+
// Prepare file uploads
130+
$post = [];
131+
foreach ($_FILES as $name => $file) {
132+
$post[$name] = new CURLFile($file['tmp_name'], $file['type'], $file['name']);
133+
}
134+
foreach ($_POST as $name => $value) {
135+
$post[$name] = $value;
136+
}
137+
} else {
138+
// Forward raw POST body (e.g., JSON payload)
139+
$post = $rawInput;
140+
$ct = $_SERVER['HTTP_CONTENT_TYPE'] ?? $_SERVER['CONTENT_TYPE'] ?? 'application/json';
141+
curl_setopt($this->ch, CURLOPT_HTTPHEADER, ['Content-Type: ' . $ct]);
142+
}
143+
144+
$this->log('Send To Telegram HTTP Request body: ' . json_encode($post, JSON_UNESCAPED_UNICODE));
145+
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
146+
} else {
147+
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $method);
148+
}
149+
}
98150
}
99151

100-
$proxy = new TelegramApiProxy;
101-
$proxy->setLog(false); // use logs only for debug
102-
$proxy->start();
103-
?>
152+
// -------------------------------------------------------------
153+
// Bootstrap
154+
// -------------------------------------------------------------
155+
$proxy = new TelegramApiProxy();
156+
$proxy->setLog(false); // Enable (true) only for debugging
157+
$proxy->start();

0 commit comments

Comments
 (0)