I have built an Employee Management System using Laravel 5.7. Calculating salary works fine for 100-150 employees (but taking a long time to process the data) & for more than 150 employees it is showing a time out error.
I want to add the feature to calculate the salary of all employees in one go & also reduce the processing time for the same. Would it be appropriate to use chunk() for that? If yes, how do I implement that?
Note:
The web application is for a BPO so there are so many types of logic to apply while calculating a salary. The code is too lengthy to share here, but if anyone wants to see the code, I can share it.
Front-end form screenshot
Page after calculation
<?php
public function calculate_salary(Request $request){
$this->validate($request,[
'employee_id' => 'required',
'attendance_types' => 'required',
'month' => 'required_without:choose_date',
'choose_date' => 'required_without:month'
]);
$download_salary = false;
$submit_salary = false;
if ($request->has('submit_data'))
{
$submit_salary = true;
}
else
{
$submit_salary = false;
}
if ($request->has('download_data'))
{
$download_salary = true;
}
else
{
$download_salary = false;
}
$dept = $request->input('salary_department');
$role = $request->input('salary_role');
$process = $request->input('salary_process');
$salary_dept = Department::where('id', $dept)->pluck('dept_name')->first();
$salary_role = Role::where('id', $role)->pluck('role_name')->first();
$salary_process = Process::where('id', $process)->pluck('process_name')->first();
if ($submit_salary == true || $download_salary == true)
{
$months = $request->input('month');
$month = $months[0];
$employee_ids = $request->input('employee_id');
$attendance_types = $request->input('attendance_types');
$attendance_type_temp_insert = $attendance_types[0];
$attendance_type = explode(',', $attendance_type_temp_insert);
if (!empty($request->input('choose_date')))
{
$dates = $request->input('choose_date');
$date = $dates[0];
}
else
{
$date = "";
}
}
else
{
$month = $request->input('month');
$employee_ids = $request->input('employee_id');
$attendance_type = $request->input('attendance_types');
$attendance_type_temp_insert = implode(',', $request->input('attendance_types'));
$date = $request->input('choose_date');
}
// Get start & end dates
$data = $this->get_salary_dates($month, $date);
$start_date = $data['start_date'];
$end_date = $data['end_date'];
$salary_start_date = $start_date->toDateString();
$salary_end_date = $end_date->toDateString();
$working_days_by_month = $this->get_working_days_of_given_month($start_date, $end_date);
$working_days = $working_days_by_month['working_days'];
$no_days = $working_days_by_month['no_days'];
Schema::create('temp_salary', function (Blueprint $table) {
$table->increments('id');
$table->integer('employee_id');
$table->string('employee_name');
$table->integer('working_days');
$table->float('emp_working_days');
$table->float('basic');
$table->float('hra');
$table->float('conveyance');
$table->float('spcl_inc');
$table->float('gross_salary');
$table->float('pf');
$table->float('esi');
$table->integer('headphone');
$table->integer('id_card');
$table->float('deductions');
$table->integer('pl_balance');
$table->integer('combo_balance');
$table->float('net_payable');
$table->string('month')->nullable();
$table->string('attendance_types');
$table->string('choose_date')->nullable();
$table->string('department')->nullable();
$table->string('role')->nullable();
$table->string('process')->nullable();
$table->timestamps();
$table->temporary();
});
$csv[] = ['Employee ID', 'Name','Department','Role','Process','Bank','Bank Account Number', 'Basic', 'HRA', 'Conveyance', 'Spcl Inc', 'Gross Salary','PF', 'ESI', 'Deductions', 'Total Working Days', 'Net Payable','Salary Month', 'Salary Start Date','Salary End Date'];
$csv1[] = ['Employee ID', 'Name','Department','Role','Process','Bank','Bank Account Number', 'Basic', 'HRA', 'Conveyance', 'Spcl Inc', 'Gross Salary','PF', 'ESI', 'Deductions', 'P','H','A','WO','WOP','WOH','UAL','Paid Leaves','PL','Combo','ual_deduct','Total Working Days', 'Net Payable','Salary Month', 'Salary Start Date','Salary End Date'];
foreach($employee_ids as $id) {
if($submit_salary == true){
DB::table('attendances')->where('employee_id', '=', $id)->whereBetween('attendance_date', [$start_date, $end_date])->update(['salary_status' => 1]);
}
$employee = Employee::find($id);
$name = $employee->name;
$emp_role = $employee->empRole->role_name;
$emp_department = $employee->empDepartment->dept_name;
$emp_process = $employee->empProcess->process_name;
$bank_account_number = $employee->bank_account_number;
$bank_name = $employee->bank_name;
$salary = Salary::where('employee_id', $id)->first();
$pl_balance = $salary->pl_balance;
$combo_balance = $salary->combo_balance;
$attendances = DB::table('attendances')->where('employee_id', '=', $id)->get();
if ($attendances->count() > 0)
{
foreach($attendances as $attendance)
{
$att_id = $attendance->id;
$att_date = Carbon::parse($attendance->attendance_date);
$dialer_in = strtotime($attendance->dialer_in_time);
$dialer_out = strtotime($attendance->dialer_out_time);
$bio_in = strtotime($attendance->biometric_in_time);
$bio_out = strtotime($attendance->biometric_out_time);
$bio_diff = $bio_out - $bio_in;
$crm_in = strtotime($attendance->crm_in_time);
$crm_out = strtotime($attendance->crm_out_time);
$week_off = $attendance->week_off;
$combo = $attendance->combo;
$holiday = $attendance->holiday;
$ual = $attendance->ual;
$dialer_duration = $attendance->dialer_difference;
$bio_duration = $attendance->biometric_difference;
$crm_duration = $attendance->crm_difference;
$chkatt = $this->get_attendance($attendance_type, $attendance->dialer_in_time, $attendance->dialer_out_time,$attendance->crm_in_time,$attendance->crm_out_time, $dialer_duration, $bio_duration, $crm_duration);
$attendance_status = $this->attendance_status($id, $chkatt, $holiday, $week_off, $ual);
DB::table('attendances')->where('id', $att_id)->update(['attendance_status' => $attendance_status]);
//echo $attendance_status;
}
}
$totalWorkingDays = $this->get_work_days($id,$start_date,$end_date,$combo_balance,$pl_balance, $submit_salary);
$totalWorkingDays = number_format((float)$totalWorkingDays, 2, '.', '');
$salary_data = $this->get_calculated_salary_data($no_days, $totalWorkingDays, $id, $submit_salary);
$basic = $salary_data['basic'];
$hra = $salary_data['hra'];
$conveyance = $salary_data['conveyance'];
$spcl_inc = $salary_data['spcl_inc'];
$gross_salary = $salary_data['gross_salary'];
$pf = $salary_data['pf'];
$esi = $salary_data['esi'];
$hp_charges = $salary_data['hp_charges'];
$idcard_charges = $salary_data['idcard_charges'];
$deductions = $salary_data['deductions'];
$net_payable = $salary_data['net_payable'];
DB::table('temp_salary')->insert(['employee_id' => $id, 'employee_name' => $name, 'working_days' => $working_days, 'emp_working_days' => $totalWorkingDays, 'basic' => $basic, 'hra' => $hra, 'conveyance' => $conveyance, 'spcl_inc' => $spcl_inc, 'gross_salary' => $gross_salary, 'pf' => $pf, 'esi' => $esi, 'headphone' => $hp_charges, 'id_card' => $idcard_charges, 'deductions' => $deductions, 'pl_balance' => $pl_balance, 'combo_balance' => $combo_balance, 'net_payable' => $net_payable, 'month' => $month, 'attendance_types' => $attendance_type_temp_insert, 'choose_date' => $date, 'department' => $salary_dept, 'role' => $salary_role, 'process' => $salary_process]);
$csv[] = [$id, $name, $emp_department, $emp_role, $emp_process, $bank_name, $bank_account_number, $basic, $hra, $conveyance, $spcl_inc, $gross_salary, $pf, $esi, $deductions, $totalWorkingDays, $net_payable, $month, $start_date, $end_date];
$get_days_status = $this->get_days_status($id, $start_date, $end_date);
$pCount = $get_days_status['pCount'];
$HalfDaysCount = $get_days_status['hCount'];
$lateLeaveCount = $get_days_status['late_leave'];
$wopCount = $get_days_status['wopCount'];
$leaves_count = $get_days_status['leaves_count'];
$UalCount = $get_days_status['UalCount'];
$woCount = $get_days_status['woCount'];
$wohCount = $get_days_status['wohCount'];
$ual_deduct = ($UalCount * 1.5) - $UalCount;
$get_paid_leaves_row = $get_days_status['pl_leaves'];
$csv1[] = [$id, $name, $emp_department, $emp_role, $emp_process, $bank_name, $bank_account_number, $basic, $hra, $conveyance, $spcl_inc, $gross_salary, $pf, $esi, $deductions, $pCount,$HalfDaysCount,$leaves_count,$woCount,$wopCount,$wohCount,$UalCount,$get_paid_leaves_row,$pl_balance, $combo_balance,$ual_deduct, $totalWorkingDays, $net_payable, $month, $start_date, $end_date];
}
$datas = DB::table('temp_salary')->get();
if($submit_salary == true){
return Excel::create('Employee_salary_report', function($excel) use ($csv) {
$excel->sheet('Employee_salary_report', function($sheet) use ($csv) {
$sheet->fromArray($csv, null, 'A1', false, false)
->getStyle('A1')
->getAlignment()
->setWrapText(true);
});
})->download('csv');
}
if($download_salary == true){
return Excel::create('salary_report', function($excel) use ($csv1) {
$excel->sheet('salary_report', function($sheet) use ($csv1) {
$sheet->fromArray($csv1, null, 'A1', false, false)
->getStyle('A1')
->getAlignment()
->setWrapText(true);
});
})->download('csv');
}
Schema::drop('temp_salary');
$departments = Department::all();
$processes = Process::all();
$roles = Role::all();
return view('sys_mg.salaries.get-salary')->with(['datas'=>$datas,'departments' => $departments, 'processes' => $processes, 'roles' => $roles, 'salary_dept' => $salary_dept, 'salary_role' => $salary_role, 'salary_process'=>$salary_process, 'salary_month'=>$month,'salary_startDate' => $salary_start_date, 'salary_endDate' => $salary_end_date, 'attendance_check_type' => $attendance_type]);
}
This is a huge process, doing many things at once, some of them deeply nested in each other.
The function is very, very long, which means it probably needs to be abstracted into various methods and classes (better OOP).
You may also be running into the N+1 problem with some of your Laravel queries, although it's hard to say at a glance.
I would recommend using Laravel's Queues, and adding each employee's payroll calculation to the queue: https://laravel.com/docs/5.8/queues
You can then use a worker process to perform each one individually.
All the database updates and transactions means PHP is constantly going to-and-fro from your database. Try to perform as many operations in pure code as possible, and then once completed, write to the DB. (Where possible, this is not a blanket rule).
Initially I would say, consider creating a SalaryCalculator class with methods such as getAttendances() and calculateSalaryFromEmployeeAttendances().
Separately, create a CSV exporter class. Process all your payroll calculations first, store the results in the DB, and then convert to CSV on demand later.
You'll refactor this later once you are able to look at all the different parts, someone else may be able to suggest a better way to break it down, but in some ways there are no right answers... just start with some OOP and abstraction of methods, and it will get better.
Use microtime(true) to get and calculate the time differences between when you start and finish operations, to start to track how long each function runs for... and go looking for the big optimisations first. What is the slowest part? Why?
You could probably ask a dozen Stack Overflow questions to optimise each of those methods, and that's Ok!
I am using CodeIgniter. I am working on the small project which is a Batch list. Now If an admin wants to create the batch list then should enter the start date and end date and start time and end time then it will check in the database that batch is running on the same date and time? If yes then it will display the message if not then it will create a new batch list.
If the date is the same the time should be different.
Now My logic is,
I am comparing the first new_start_date with exist_start_date and exist_end_date if date found in between then it will check the time.
It's working till date compare. Even it's checking the time but from there how to exit the process and call the JSON? because from there my JSON not working.
I added "echo "time not match";" from there I am not able to call the JSON I am getting the output on my network tab.
I am getitng the output
enter 1enter 2{"error":true,"msg":"Batch Created"}time not match
Would you help me out in this?
$id = $this->input->post('venue_id');
$venue_id = implode(',',$id);
$activity_list_id = $this->input->post('activity_name');
$new_batch_start_date = date('Y-m-d',strtotime($this->input->post('start_date')));
$new_batch_end_date = date('Y-m-d',strtotime($this->input->post('end_date')));
$new_batch_start_time = $this->input->post('start_time');
$new_batch_end_time = $this->input->post('end_time');
$days = implode(',',$this->input->post('days'));
//print_r($days);
if($new_batch_start_date >= $new_batch_end_date)
{
$response['error'] = false;
$response['msg'] = "End Date Should be Greater than Start Date";
echo json_encode($response);
return false;
}
//convert in Time Format
$new_batch_start_time = strtotime($new_batch_start_time);
$new_batch_end_time = strtotime($new_batch_end_time);
$venue = $this->input->post('name');
$data = array(
'activity_list_id' => $this->input->post('activity_name'),
'batch_venue_id' => $venue_id,
'batch_name' => $this->input->post('batch_name'),
'start_date' => date('Y-m-d',strtotime($this->input->post('start_date'))),
'end_date' => date('Y-m-d',strtotime($this->input->post('end_date'))),
'start_time' => $this->input->post('start_time'),
'end_time' => $this->input->post('end_time'),
'total_capacity' => $this->input->post('total_capecity'),
'batch_status' => 1,
'created_by' => trim($this->session->userdata['login_data']['user_id']),
'created_date' => date('d-m-Y h:i:s A'),
'batch_days' => $days
);
$get_batch_details = $this->Batch_model->fetchBatches();
if(!empty($get_batch_details))
{
foreach ($get_batch_details as $rows)
{
$exist_batch_start_date = $rows->start_date;
$exist_batch_end_date = $rows->end_date;
$batch_time1 = strtotime($rows->start_time);
$batch_time2 = strtotime($rows->end_time);
$batch_venue_id = explode(',',$rows->batch_venue_id);
$common_venue_id = array_intersect($id,$batch_venue_id);
//print_r($common_venue_id);
if($common_venue_id)
{
echo "enter 1";
//if new batch start date between existing batch start date
if($exist_batch_start_date <= $new_batch_start_date && $exist_batch_end_date >= $new_batch_start_date ){
echo "enter 2";
if($batch_time1 <= $new_batch_start_time && $batch_time2 > $new_batch_start_time){
$msg = "Other Batch Alredy Running On from Date $batch_start_date to $exist_batch_end_date on Time : $batch_time1 to $batch_time2.
Please Change Time Slot or Start And End Date";
$response['error'] = false;
$response['msg'] = $msg;
echo json_encode($response);
exit;
}
else{
$result = $this->Batch_model->createBatch($data);
echo "time not match";
print_r($result);
}
break;
}
//if date is different
else
{
$result = $this->Batch_model->createBatch($data);
}
}else
{
$result = $this->Batch_model->createBatch($data);
}
}
}
//first time creating batch
else
{
$result = $this->Batch_model->createBatch($data);
}
Mobel
function createBatch($data){
if($this->db->insert('batch_list',$data))
{
$response['error'] = true;
$response['msg'] = "Batch Created";
echo json_encode($response);
}
else
{
$response['error'] = true;
$response['msg'] = "Failed to Create Batch";
echo json_encode($response);
}
}
function fetchBatches()
{
$result = $this->db->where(['batch_list.batch_status'=>1,'activity_list.act_status'=>1])
->from('batch_list')
->join('activity_list','activity_list.activity_id = batch_list.activity_list_id')
->get()
->result();
return $result;
}
Ajax
success: function(response){
var data = JSON.parse(response);
if (data.error == true){
swal({
title: "Success",
text: data.msg ,
type: "success"
}).then(function(){
location.reload();
}
);
} else {
swal({
title: "Warning",
text: data.msg ,
type: "warning"
});
}
}
Would you help me out in this issue?
your entire approach is a bit messy because you find yourself in a ton of redundant code fragments and nobody is able to understand what exactly you want - i gv you some hints here including an example based on your code
Use Exceptions - it's perfect for your case - if something goes wrong - stop it
Try to filter your need to an extent of one single task und try to solve it - and only after that go to the next task
Always - remember always - think about one term - if you find repeatedly the same code in your application - you know something is wrong - and you should refactor it - don't be ashamed about redundancies - they do always happen - but if you find them, you must refactor those code snippets
Now to your example
What are your tasks here ?
you can try to ask your database if a batch is already running - you dont need to iterate over the entire table entries
Compare both input Dates from Administrator - if start date is in the future of end date, instantely stop the application
your intersection isn't really clear to me what you want to achieve here - but i'm really convinced you can ask the database here too (catchword: find_in_set)
Based on that information we can start to develop things now ;) (if i don't have everything just complete the list above and try to implement your task)
Controller:
try
{
$id = $this->input->post('venue_id');
$venue_id = implode(',',$id);
$activity_list_id = $this->input->post('activity_name');
$new_batch_start_date = date('Y-m-d',strtotime($this->input->post('start_date')));
$new_batch_end_date = date('Y-m-d',strtotime($this->input->post('end_date')));
$new_batch_start_time = $this->input->post('start_time');
$new_batch_end_time = $this->input->post('end_time');
$days = implode(',',$this->input->post('days'));
$objDateStart = DateTime::createFromFormat('Y-m-d h:i a', $new_batch_start_date.' '.$new_batch_start_time);
$objDateEnd = DateTime::createFromFormat('Y-m-d h:i a', $new_batch_end_date.' '.$new_batch_end_time);
if ($objDateEnd < $objDateStart) throw new Exception('End Date Should be Greater than Start Date');
if ($this->Batch_model->hasBatchesBetweenDates($objDateStart, $objDateEnd)) throw new Exception('Other Batch already running On from '.$objDateStart->format('d-m-Y H:i').' to '.$objDateEnd->format('d-m-Y H:i').'. Please Change Time Slot for Start and End Date');
$data = array(
'activity_list_id' => $this->input->post('activity_name'),
'batch_venue_id' => $venue_id,
'batch_name' => $this->input->post('batch_name'),
'start_date' => $objDateStart->format('Y-m-d'),
'end_date' => $objDateEnd->format('Y-m-d'),
'start_time' => $objDateStart->format('H:i'),
'end_time' => $objDateEnd->format('H:i'),
'total_capacity' => $this->input->post('total_capecity'),
'batch_status' => 1,
'created_by' => trim($this->session->userdata['login_data']['user_id']),
'created_date' => date('d-m-Y h:i:s A'),
'batch_days' => $days
);
$this->Batch_model->createBatch($data);
}
catch(Exception $e)
{
$arrError = [
'error' => false,
'msg' => $e->getMessage()
];
echo json_encode($arrError);
}
Model:
public function hasBatchesBetweenDates(DateTime $objDateStart, DateTime $objDateEnd)
{
$query = $this->db
->from('batch_list')
->join('activity_list','activity_list.activity_id = batch_list.activity_list_id')
->where('CONCAT(start_date,\' \',start_time) >=', $objDateStart->format('Y-m-d H:i:s'))
->or_group_start()
->where('CONCAT(end_date, \' \', end_time) <=', $objDateEnd->format('Y-m-d H:i:s'))
->where('CONCAT(end_date, \' \', end_time) >=', $objDateStart->format('Y-m-d H:i:s'))
->group_end()
->get();
return ($query->num_rows() > 0);
}
i hope you understand the concepts here - if you've questions - don't hesitate to ask
I have two tables, dishes and days_avail, where dishes contains information regarding dishes cooked and days_avail contains what days a certain dish is available.
days_avail looks like this:
daysid || dishid || monday || tuesday || wednesday || friday
daysid: unique id
dishid: dish id from dishes table
Mon - Fri: boolean
So, what I am able to do is pull the dishes and show relevant info along with what day it is available on. However, what I am trying to accomplish is categorizing the dishes by the days they are available. So something like this:
Monday
dish name
dish desc desc desc
Tuesday
Dish name
dish desc dish desc
My query is as follows:
$sql = "SELECT * FROM dishes JOIN days_avail ON days_avail.dishid = dishes.id WHERE user_id = :cookid ORDER BY days_avail.daysid";
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':cookid' => $cookid
));
}
catch(Exception $error) {
echo '<p class="bg-danger">', $error->getMessage(), '</p>';
}
while($row = $stmt->fetch()) {
$dish_name = $row['dish_name'];
$dish_desc = $row['dish_desc'];
$dish_price = $row['dish_price'];
$mon = $row['Monday'];
$tues = $row['Tuesday'];
$wed = $row['Wednesday'];
$thurs = $row['Thursday'];
$fri = $row['Friday'];
}
I can't group the dishes under one day its available. I have tried using a if statement (example: if($mon == 1) { echo "Monday // dish_info, etc" }) but this results in the heading being repeated for each dish.
I have also tried using java handlebars to more or less run a query and then simply "stuff" the results in the (appropriate) div boxes but did not work.
I am get a complete lost here. I would greatly appreciate any help.
Thank you
You can do this by putting your returned rows into an array, based off the day available-
...your query code...
$days=array('Monday'=>array(),'Tuesday'=>array(),'Wednesday'=>array(),'Thursday'=>array(),'Friday'=>array());
while($row = $stmt->fetch()) {
foreach($days as $day=>$array){
if($row[$day]){
$days[$day][]=array('dish_name'=>$row['dish_name'],
'dish_desc'=>$row['dish_desc'],
'dish_price'=>$row['dish_price']);
}
}
}
now just loop over your $days array
foreach($days as $day => $dishes){
echo "<h2>$day</h2>";
foreach($dishes as $dish){
echo $dish['dish_name']."<br />";
echo $dish['dish_desc']."<br />";
echo $dish['dish_price']."<br />";
}
}
Try this :)
$sql = "SELECT * FROM dishes JOIN days_avail ON days_avail.dishid = dishes.id WHERE user_id = :cookid ORDER BY days_avail.daysid";
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':cookid' => $cookid
));
}
catch(Exception $error) {
echo '<p class="bg-danger">', $error->getMessage(), '</p>';
}
$dishes = array(
'mon' = array(),
'tues' = array(),
'wed' = array(),
'thurs' = array(),
'fri' = array()
);
while ($row = $stmt->fetch()) {
$dish = array(
'name' => $row['dish_name'],
'desc' => $row['dish_desc'],
'price' => $row['dish_price']
);
$mon = (bool) $row['Monday'];
$tues = (bool) $row['Tuesday'];
$wed = (bool) $row['Wednesday'];
$thurs = (bool) $row['Thursday'];
$fri = (bool) $row['Friday'];
if ($mon) {
$dishes['mon'][] = $dish;
}
if ($tues) {
$dishes['tues'][] = $dish;
}
if ($wed) {
$dishes['wed'][] = $dish;
}
if ($thurs) {
$dishes['thurs'][] = $dish;
}
if ($fri) {
$dishes['fri'][] = $dish;
}
}
// iterate over Monday dishes
foreach ($dishes['mon'] as $dish) {
// $dish['name'], $dish['desc'], $dish['price']
}
// and so on....
I would like to ask if what is missing in my script for sending mail, my query is fine and it shows results and I'd like to ask for help on how to include those query result into the message that I will send out. I'd really appreciate it if you could give me an advice where to start. thanks.
<?php
$cfg = array(
'display' => 'gw#mail.com',
'address' => 'support#mail.com',
'subject' => 'TEST '
. date("m/d/t h:i:s A", strtotime('TODAY')) . ' hits',
'queries' => array(
"SELECT inbox.src AS 'From Mobile Number', outbox.dst AS 'To Mobile Number', outbox.stamp AS 'Timestamp', inbox.data AS 'Message', outbox.status AS 'Status' FROM mega.outbox LEFT JOIN mega.inbox ON outbox.pid=inbox.pid WHERE outbox.sid=156 && inbox.sid=156 && stamp > NOW() - INTERVAL 3 HOUR",
),
);
include "/var/xrelay/mysql.php";
$sql = new database();
$msg = '';
foreach( $cfg['queries'] as $i ) {
$tmp = $sql->read($i, true);
if (!empty($tmp)) {
foreach($tmp[0] as $k => $v) $msg .= "$k: $v\r\n";
}
}
foreach( preg_split( '/[\s,]+/', $cfg['address'], -1, PREG_SPLIT_NO_EMPTY) as $i ) {
$sql->write("INSERT INTO mega.emails (sender,recipient,subject,message,stamp) VALUES "
. "('{$cfg['display']}','$i','{$cfg['subject']}','".$sql->escape($msg)."', NOW());");
}
?>
Is there any way to improve this more? this mailer supposed to send mail to a recipient every 3hours if there are any activity from the db. it will retrieve data last 3 hours ago and put the result as message.
include "/var/xrelay/mysql.php";
$sql = new database('sql://gateway:xrelay#00.000.000.000/test');
$cfg = array(
'display' => 'gw#mail.com',
'address' => 'g#mail.com',
'subject' => 'MAIL HITS ' . date("m/d/y h:i:s A", strtotime("NOW")) . ' hits',
);
//define('DEBUG',true);
$result = mysql_query("SELECT outbox.dst, DATE_FORMAT(outbox.stamp,'%b-%d-%Y %h:%i %p')AS 'Stamp', outbox.status FROM mega.outbox LEFT JOIN mega.inbox ON outbox.pid=inbox.pid WHERE outbox.sid=156 && inbox.sid=156 && outbox.stamp > NOW() - INTERVAL 3 HOUR");
$msg='| Mobile# | Timestamp | Status |\r\n';
while($row = mysql_fetch_assoc($result))
{
$msg .= "| ". $row['dst'] ." | ". $row['Stamp'] ." | ". $row['status'] ." |\r\n";
}
$num_rows = mysql_num_rows($result);
echo $msg;
if($num_rows != 0){
foreach( preg_split( '/[\s,]+/', $cfg['address'], -1, PREG_SPLIT_NO_EMPTY) as $i ) {
$sql->write("INSERT INTO mega.emails (sender,recipient,subject,message,stamp) VALUES " . "('{$cfg['display']}','$i','{$cfg['subject']}','". $msg ."', NOW());");
}
}
?>
Once you have the results you should create a string that you would append to the body of the e-mail. You can use sprintf for this purpose.
If you are looking for a way to send the actual e-mail, the mail function is explained here.