PNM Portal API Analysis: A Case Study¶
This section demonstrates how to analyze the API used by the PNM (Pamantasan ng Montalban / Colegio de Montalban) student portal. We will cover the login process, data retrieval, and document generation.
Important Note
This example is for educational purposes only. Accessing or using this API without authorization is illegal and unethical. Respect website terms of service and avoid any actions that could harm the system or violate student privacy.
Important Note
The information provided here is based on publicly accessible data and observations of network traffic. It should not be used to access or manipulate student data without explicit permission.
1. Understanding the Login Process¶
The login process involves the following steps:
- Submitting Credentials: The user submits their student ID, email address, and password to the
https://portal.pnm.edu.ph/v2/login.phpendpoint using a POST request. - Accessing the Dashboard: Upon successful authentication (as determined by cookies), the user is redirected to the main dashboard at
https://portal.pnm.edu.ph/index. The intermediate redirect toauth-redirectcan be skipped.
Replicating the Login with Python:
import requests
from bs4 import BeautifulSoup
def login_to_pnm(student_id, email, password):
"""Logs into the PNM portal and returns the session object if successful,
otherwise returns None.
"""
login_url = "https://portal.pnm.edu.ph/v2/login.php"
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "en-US,en;q=0.9",
"cache-control": "max-age=0",
"content-type": "application/x-www-form-urlencoded",
"dnt": "1",
"origin": "https://portal.pnm.edu.ph",
"priority": "u=0, i",
"referer": "https://portal.pnm.edu.ph/v2/login",
"sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Linux"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "same-origin",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
}
data = {
"studentid": student_id,
"emailaddress": email,
"password": password,
"login": ""
}
session = requests.Session() # Use a session to persist cookies
response = session.post(login_url, headers=headers, data=data, allow_redirects=False)
# Check for successful login by examining the response from the index page
index_url = "https://portal.pnm.edu.ph/index"
index_response = session.get(index_url, headers=headers) # Get the index page
if index_response.status_code == 200:
soup = BeautifulSoup(index_response.text, 'html.parser')
welcome_message = soup.find("div", class_="sidenav-footer-title") # Look for the welcome msg on the index page
if welcome_message:
print("Login Successful!")
return session
else:
print("Login Failed: Could not find welcome message on the index page.")
print("HTML Content of Index Response:\n", index_response.text) # Print for debug
return None
else:
print("Login Failed: Could not retrieve index page (status code:", index_response.status_code, ")")
return None
# Example usage (replace with valid credentials):
session = login_to_pnm("YOUR_STUDENT_ID", "YOUR_EMAIL", "YOUR_PASSWORD")
if session:
# Now you can use the session to access other API endpoints
pass # Proceed to the dashboard and other data retrieval
Explanation:
login_to_pnm()handles login with student ID, email, and password.- Sets headers/data for the POST request to the login URL.
requests.Session()is used to store login cookies.- Code retrieves the
/indexpage and checks for a welcome message to confirm login success. Returns the session if successful, otherwiseNone. - Illustrates basic login. More complex systems may use CSRF tokens or CAPTCHAs.
2. Retrieving Enrolled Courses¶
Once logged in, you can retrieve the enrolled courses by sending a POST request to https://portal.pnm.edu.ph/getEnrolledCourses.php with the student ID. The server returns a JSON response containing the course information.
Python Code:
if session: # Assuming you have a valid session from the login
courses_url = "https://portal.pnm.edu.ph/getEnrolledCourses.php"
courses_headers = {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"dnt": "1",
"origin": "https://portal.pnm.edu.ph",
"priority": "u=1, i",
"referer": "https://portal.pnm.edu.ph/enrollment3",
"sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Linux"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest"
}
courses_data = {
"student_id": "YOUR_STUDENT_ID" # Replace with the actual student ID
}
courses_response = session.post(courses_url, headers=courses_headers, data=courses_data)
if courses_response.status_code == 200:
courses_json = courses_response.json()
print("Enrolled Courses:", courses_json)
else:
print("Failed to retrieve enrolled courses.")
Explanation:
- This code assumes you have a valid
sessionobject from the login function. - It constructs the headers and data for the
getEnrolledCourses.phpPOST request. - It uses
session.post()to send the request, ensuring that the cookies are included. - It parses the JSON response and prints the course information.
3. Downloading Documents (OVRF, COE, SOG)¶
The API provides endpoints for generating and downloading documents such as the OVRF, Certificate of Enrollment (COE), and Summary of Grades (SOG). These endpoints typically return PDF files.
- Generating OVRF: POST request to
https://portal.pnm.edu.ph/generateOVRF.phpwithstudent_id. - Generating COE: POST request to
https://portal.pnm.edu.ph/generateCOE.phpwithstudent_idandpurpose. Thepurposeparameter accepts values like "Scholarship Applications", "Internship Requirements", etc. - Generating SOG: POST request to
https://portal.pnm.edu.ph/generateSOG.phpwithstudent_idandpurpose. Thepurposeparameter is similar to the COE endpoint.
Python Code (Example for COE):
if session: # Assuming a valid session
coe_url = "https://portal.pnm.edu.ph/generateCOE.php"
coe_headers = {
"accept": "*/*",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/x-www-form-urlencoded",
"dnt": "1",
"origin": "https://portal.pnm.edu.ph",
"priority": "u=1, i",
"referer": "https://portal.pnm.edu.ph/enrollment3",
"sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Linux"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
}
coe_data = {
"student_id": "YOUR_STUDENT_ID", # Replace
"purpose": "Scholarship Applications" # Or other valid purpose
}
coe_response = session.post(coe_url, headers=coe_headers, data=coe_data)
if coe_response.status_code == 200:
with open("certificate_of_enrollment.pdf", "wb") as f:
f.write(coe_response.content)
print("COE downloaded successfully as certificate_of_enrollment.pdf")
else:
print("Failed to download COE.")
Python Code (Example for OVRF):
if session: # Assuming a valid session
ovrf_url = "https://portal.pnm.edu.ph/generateOVRF.php"
ovrf_headers = {
"accept": "*/*",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/x-www-form-urlencoded",
"dnt": "1",
"origin": "https://portal.pnm.edu.ph",
"priority": "u=1, i",
"referer": "https://portal.pnm.edu.ph/enrollment3",
"sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Linux"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
}
ovrf_data = {
"student_id": "YOUR_STUDENT_ID" # Replace
}
ovrf_response = session.post(ovrf_url, headers=ovrf_headers, data=ovrf_data)
if ovrf_response.status_code == 200:
with open("ovrf.pdf", "wb") as f:
f.write(ovrf_response.content)
print("OVRF downloaded successfully as ovrf.pdf")
else:
print("Failed to download OVRF.")
Explanation:
- This code shows how to download the COE. The process is similar for OVRF and SOG.
- It sets the appropriate headers and data for the POST request.
- It uses
session.post()to send the request. - If the request is successful, it saves the PDF content to a file.
4. Retrieving Grades¶
Grades can be retrieved via a POST request to https://portal.pnm.edu.ph/test2.php with student_id. The response is a JSON array of objects, each containing subject code, description, and grade.
Python Code:
if session:
grades_url = "https://portal.pnm.edu.ph/test2.php"
grades_headers = {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"dnt": "1",
"origin": "https://portal.pnm.edu.ph",
"priority": "u=1, i",
"referer": "https://portal.pnm.edu.ph/grades",
"sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Linux"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest"
}
grades_data = {
"student_id": "YOUR_STUDENT_ID"
}
grades_response = session.post(grades_url, headers=grades_headers, data=grades_data)
if grades_response.status_code == 200:
grades_json = grades_response.json()
print("Grades:", grades_json)
else:
print("Failed to retrieve grades.")
5. Other Endpoints and Data¶
- Evaluated Instructors:
https://portal.pnm.edu.ph/fetchEval.php?student_id=.... This endpoint requires no authentication and returns a list of instructors to be evaluated. - E-books:
https://portal.pnm.edu.ph/getEbooks.php. This endpoint requires no authentication and returns a list of available e-books.
6. Important Notes¶
- Session Management: The
PHPSESSID,session_iv, andsession_idcookies are crucial for maintaining the session. Therequests.Session()object automatically handles these cookies. - Headers: Pay close attention to the headers, especially
Content-Type,Referer, andUser-Agent. - Authentication: The code assumes you have valid credentials. Gaining access to credentials without authorization is illegal.
- Rate Limiting: Be careful not to overload the server with too many requests. Implement delays if necessary.
- Legal and Ethical Considerations: Unauthorized access to student data is a serious offense. Only perform these actions with explicit permission and for legitimate educational purposes.
- Cloudflare: The presence of
cf_clearancecookie suggests Cloudflare protection. This may require additional handling to bypass.
7. Identifying Logged-In State¶
Several indicators can determine if a user is logged in:
- The presence of specific cookies (
PHPSESSID,session_iv,session_id). - Redirection to the dashboard (
https://portal.pnm.edu.ph/index). - The presence of the welcome message and student name in the dashboard HTML.
- The existence of menu items such as "Enrolled Courses," "Grades," and "Evaluation."
Disclaimer¶
This document is intended for educational purposes only and should not be used for any illegal or unethical activities. Accessing or manipulating student data without authorization is strictly prohibited. Always respect website terms of service and avoid any actions that could harm the system or violate student privacy. The author assumes no responsibility for any misuse of the information provided herein.