retrieve data from online database using input file - sql

Im using Postgres 9.3 on MacOSX.
I would be very happy if anyone could point me in the right direction here. I would like to write a function which connects to an existing (online) database (e.g. this one) and retrieves data (in this case shapefiles) using an input file with appropriate strings (in this case MRGIDs). Im sorry I don't have any code, I literally don't know where to start and I don't seem to find any threads on it. Maybe SQL isn't the way to go here?
Input file example;
species,mrgids
Sp1,4279
Sp1,8366
Sp1,21899
Sp1,21834
Sp1,7130
Sp1,1905
Sp1,21900
Sp1,5679
Sp1,5696
Thanks!

This is almost certainly done best outside the database, using a script in your choice of language. I'd use Python and psycopg2, but things like Ruby + the Pg gem, Perl and DBI / DBD::Pg, or even PHP and PDO, are equally reasonable choices.
Your code can do an HTTP fetch, then (if it's CSV-like) use the COPY command to load the data into PostgreSQL. If it's a shapefile, you can feed the data to PostGIS's shp2pgsql loader, or make individual INSERTs using the GeomFromText PostGIS function.
You could do the HTTP fetch from a PL/Pythonu or PL/Perlu stored procedure, but there'd be no real benefit over just doing it from a script, and it'd be more robust as an external script.
So, really, you need to split this problem up.
You'll need code to talk to the website(s) of interest, possibly including things like HTTP POSTs to submit forms. Or, preferably, use a web API for the site(s) that's designed for automatic scripted interaction. Most simple RESTful APIs are easy to use from scripting languages using libraries like Perl's LWP, Python's httplib, etc. In the case of the site you linked to, as user623952 mentioned, there's a RESTful API.
Then you'll need code to fetch the data of interest, and code to read the fetched data and load it into PostgreSQL. You might want to download all the data then load it, or you may want to stream it into the database as it's downloaded (pipe to shp2pgsql, etc).

this a very basic example with with PHP and CURL
I used your input file exactly and saved it as input.txt
species,mrgids
Sp1,4279
Sp1,8366
Sp1,21899
Sp1,21834
Sp1,7130
Sp1,1905
Sp1,21900
Sp1,5679
Sp1,5696
and this is the PHP and CURL doing its stuff:
<?php
$base_url = "http://www.marineregions.org/rest/getGazetteerRecordByMRGID.json/%s/";
// just get the input file into an array to use
$csv = read_file("input.txt");
// if you want to see the format of $csv
print "<pre>".print_r($csv,true)."</pre>";
// go through each csv item and run a curl request on it
foreach($csv as $i => $data)
{
$mrgids = $data['mrgids'];
$url = sprintf($base_url,$mrgids);
$response = run_curl_request($url);
if ($response!==false)
{
//http://us2.php.net/manual/en/function.json-decode.php
$json = json_decode($response,true);
if (!is_null($json))
{
// this is where you would write the code to stick this info in
// your DB or do whatever you want with it...
print "<pre>$url \n".print_r($json,true)."\n\n</pre>";
}
else
{
print "error: response was not proper JSON for $url <br/><br/>";
print $response."<br/><br/><br/>";
}
}
else
{
print "error: response was false for $url <br/><br/>";
}
}
function read_file($filename, $has_headers=true, $assoc=true)
{
$headers = array();
$row = 1;
if (($handle = fopen($filename, "r")) !== FALSE)
{
$return = array();
if ($has_headers)
{
if (($data = fgetcsv($handle, 1000, ",")) !==false)
{
$headers = $data;
}
}
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
if ($assoc)
{
$temp = array();
foreach($headers as $hi => $header)
{
$temp[$header] = (isset($data[$hi])) ? $data[$hi] : '';
}
$return[] = $temp;
}
else
{
$return[] = $data;
}
}
fclose($handle);
}
else
{
$return = false;
}
return $return;
}
// requires PHP CURL extension
// http://php.net/manual/en/function.curl-setopt.php
function run_curl_request($url)
{
// create curl resource
$ch = curl_init();
$defaults = array(
CURLOPT_POST => false,
CURLOPT_HEADER => false,
CURLOPT_URL => $url,
CURLOPT_FRESH_CONNECT => true,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FORBID_REUSE => true,
CURLOPT_TIMEOUT => 4
);
curl_setopt_array($ch, $defaults);
// $output contains the output string
$output = curl_exec($ch);
// close curl resource to free up system resources
curl_close($ch);
return $output;
}
?>
And if it worked, you get a bunch of these as output:
http://www.marineregions.org/rest/getGazetteerRecordByMRGID.json/4279/
Array
(
[MRGID] => 4279
[gazetteerSource] => IHO 23-3rd: Limits of Oceans and Seas, Special Publication 23, 3rd Edition 1953, published by the International Hydrographic Organization.
[placeType] => IHO Sea Area
[latitude] => 39.749996185303
[longitude] => 5.0942182540894
[minLatitude] => 35.071937561035
[minLongitude] => -6.0326728820801
[maxLatitude] => 44.42805480957
[maxLongitude] => 16.221109390259
[precision] => 1079464.0796258
[preferredGazetteerName] => Mediterranean Sea - Western Basin
[preferredGazetteerNameLang] => English
[status] => standard
[accepted] => 4279
)
notes:
I had to do this to get CURL to work on WAMP for PHP 5.3.13
json_decde()
curl_setopt()
curl_exec()
fgetcsv()
curl_multi_exec() - look into this if you chose this route, you will want it

Related

Trying to find a file that doesnt exist Yii2

Im trying to create an email function that sends a file attached.
I've created the function and added attach() with the route of file I want to attach as follows:
public function newMonthlyBillingRegister(Clinic $clinic, ClinicMonthlyBilling $clinicMonthlyBilling)
{
$countryAdmins = $clinic->findCountryAdmins($clinic->country->id);
$adminEmails = [];
foreach ($countryAdmins as $admin) {
$adminEmails[$admin->email] = $admin->fullName;
}
/** #var BaseMailer $mailer */
$mailer = Yii::$app->mailer;
$mailer->htmlLayout = 'layouts/standard_html';
//$mailer->htmlLayout = 'layouts/invoice_html';
// $mailer->textLayout = 'layouts/invoice_text';
try{
return $mailer
->compose(
['html' => 'newMonthlyBillingRegister-html', 'text' => 'newMonthlyBillingRegister-text'],
[
'clinic' => $clinic,
'clinicMonthlyBilling' => $clinicMonthlyBilling,
]
)
->setFrom([Yii::$app->params['supportEmail'] => Yii::t('app', 'support-email-name', ['appName' => Yii::$app->name])])
->setTo($adminEmails)
->setSubject(Yii::t('app', '[CLINIC][BACKOFFICE] A clinic has upgraded its information in Guarantee Fund Modal.'))
->attach('app/media/uploads/clinic/monthly-billing/'.$clinicMonthlyBilling->trimestralBillingFile)
->queue() && YII_DEBUG && Yii::$app->mailqueue->process();
}
catch(\Exception $e){
LogService::getLogger()->error("Error while sending mail.","EmailService:newMonthlyBillingRegister()",$e->getMessage());
}
}
It gave me an error, but the problem comes when I delete attach() from my code, reverting all my changes on this email function, and when I try to send again the email the following message appears:
PHP Warning: fopen(app/media/uploads/clinic/monthly-billing/user_1_clinic_1_trimestral_billing_file_2019_05_09_08_22_35): failed to open stream: No such file or directory in /app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php on line 142
The user_1_clinic_1_trimestral_billing_file_2019_05_09_08_22_35 file doesnt exist in app/media/uploads/clinic/monthly-billing/ folder and even in my database
...what's wrong?¿ I know is in my local but I dont know the reason of trying to search a file that doesn't exist and I didn't code anything to search it,
Anyone can help? Im using PHPStorm,
Thanks a lot for your attention!
I had to clean my email queue and it worked!! Thanks a lot Insane Skull for your help ;)

export data from bigquery to cloud storage- php client library - there is one extra empty new line in the cloud storage file

I followed this sample
https://cloud.google.com/bigquery/docs/exporting-data
public function exportDailyRecordsToCloudStorage($date, $tableId)
{
$validTableIds = ['table1', 'table2'];
if (!in_array($tableId, $validTableIds))
{
die("Wrong TableId");
}
$date = date("Ymd", date(strtotime($date)));
$datasetId = $date;
$dataset = $this->bigQuery->dataset($datasetId);
$table = $dataset->table($tableId);
// load the storage object
$storage = $this->storage;
$bucketName = 'mybucket';
$objectName = "daily_records/{$tableId}_" . $date;
$destinationObject = $storage->bucket($bucketName)->object($objectName);
// create the import job
$format = 'NEWLINE_DELIMITED_JSON';
$options = ['jobConfig' => ['destinationFormat' => $format]];
$job = $table->export($destinationObject, $options);
// poll the job until it is complete
$backoff = new ExponentialBackoff(10);
$backoff->execute(function () use ($job) {
print('Waiting for job to complete' . PHP_EOL);
$job->reload();
if (!$job->isComplete()) {
//throw new Exception('Job has not yet completed', 500);
}
});
// check if the job has errors
if (isset($job->info()['status']['errorResult'])) {
$error = $job->info()['status']['errorResult']['message'];
printf('Error running job: %s' . PHP_EOL, $error);
} else {
print('Data exported successfully' . PHP_EOL);
}
I have 37670 rows in my table1, and the cloud storage file has 37671 lines.
And I have 388065 my table2, and the cloud storage file has 388066 lines.
The last line in both cloud storage files is empty line.
Is this a Google BigQuery feature improvement request? or I did something wrong in my codes above?
What you described seems like an unexpected outcome. The output file should generally has the same number of lines as the source table.
Your PHP code looks fine and shouldn't be the cause of the issue.
I'm trying reproduce it but unable to. Could you double-check if the last empty line is somehow added by another tool like a text editor or something? How are you counting the lines of the resulting output.
If you have ruled that out and are sure the newline is indeed added by BigQuery export feature, please consider opening a bug using the BigQuery Issue Tracker as suggested by xuejian and include your job ID so that we can investigate further.

whmcs server-side pagination

I'm working with WHMCS and I notice that list views are not working well.
That's because in the clientarea's list views I have tousans thousands of records to display and the DataTables is crashing.
Is there a way to paginate from the server-side? I will appreciate any idea.
Here is an idea: let' say you are viewing the Domains list page, you can use ClientAreaPage hook to create a variable to load a "paged" copy of domains:
add_hook( 'ClientAreaPage', 1, function( $vars )
{
$myVars = array();
if (App::getCurrentFilename() == 'clientarea' && isset($_GET['action']) && $_GET['action'] == 'domains') {
$domains2 = array();
foreach($vars['domains'] as $k => $domain) {
if ($k < 3) {//your code to handle pagination
$domains2[] = $domain;
}
}
$myVars['domains2'] = $domains2;
$myVars['currentpage'] = 1;
}
return $myVars;
});
In clientareadomains.tpl (template file), you need to change $domains to $domains2:
{foreach key=num item=domain from=$domains2}
Of course, it is not simple task, you need to handle pagination in the hook and the tpl files.
Hope it helps.

How can I do a SQL query to an Oracle database with Perl and get the result as JSON?

I'm working with a legacy system and need to get data out of an Oracle database using Perl. Perl is one of the languages I don't spend much time in, so I'd like to be able to run a simple SQL query and pass the data to another system via JSON.
It seems that JSON, DBI, and DBD are available on this system. I'd like to accomplish this without making too many changes or updates to the system, if possible. I believe the JSON library is at version 5.12.2
I found DBI-Link library on Github and I believe this file is almost exactly what I need:
#!/usr/bin/perl -l
use strict;
use warnings;
$|++;
use JSON;
use DBI;
use DBD::Oracle qw(:ora_types);
my $dbh = DBI->connect(
'dbi:Oracle:host=localhost;sid=xe',
'hr',
'foobar',
{
AutoCommit => 1,
RaiseError => 1,
}
);
my #methods = qw(table_info column_info primary_key_info);
foreach my $method (#methods) {
if ( $dbh->can($method) ) {
print "Handle has method $method. w00t!"
}
else {
$dbh->disconnect;
print "Sadly, handle does not have method $method. D'oh!";
exit;
}
}
my $sth=$dbh->table_info('%', '%', '%', 'TABLE');
while(my $table = $sth->fetchrow_hashref) {
my $t;
$t->{'Table Name'} = $table->{TABLE_NAME};
$t->{'Column Info'} = $dbh->column_info(
undef,
$table->{TABLE_SCHEM},
$table->{TABLE_NAME},
'%'
)->fetchall_arrayref({});
$t->{'Primary Key Info'} = $dbh->primary_key_info(
undef,
$table->{TABLE_SCHEM},
$table->{TABLE_NAME}
)->fetchall_arrayref({});
print map {"$_: ". json_encode($t->{$_})} grep{ defined $t->{$_} } 'Table Name', 'Column Info', 'Primary Key Info';
print;
}
$sth->finish;
$dbh->disconnect;
The Error
I've installed the dependencies but when I run it I am getting:
Undefined subroutine &main::json_encode called at ./oracle.t line 47.
I searched the rest of the source in that repository and don't see any my json_encode definition, so maybe I have a version of the JSON library that is too old is my possible idea, but it seems unlikely that the json_encode method would have changed names.
The Next Steps
After I get json_encode to work I know I will need to execute a custom query and then save the data, it would be something like this:
$sth = $dbh->prepare("select * from records where pending = 1");
$sth->execute;
my $records = new HASH;
while($r = $sth->fetchrow_hashref)
{
$records << $r
}
my $json = json_encode($records)
However I'm unsure how to build the $records object for encoding so any help would be appreciated. I have searched stackoverflow, google, and github for perl examples of oracle to json and only had luck with the code from that DBI-Link repo.
According to the documentation for the JSON module, the function you want is encode_json and not json_encode.
I'd probably store the records in an array of hashes; something like this:
my #records;
while (my $r = $sth->fetchrow_hashref)
{
push(#records, $r);
}
If you know what field you want a hash-of-hashes keyed on:
my %records;
while (my $r = $sth->fetchrow_hashref)
{
$records{ $r->{key_field} } = $r;
}

How to store file and retrive it correctly with moodle file api?

i'm programming a mod activity for moodle which load files and show'em to any student who can access to the course.
The problem is that handing files in moodle is damn hard.
this is what i have done so far:
option page with importers
$mform->addElement('filepicker', 'slidesyncmedia', get_string('slidesyncmedia', 'slidesync'), null, array('maxbytes' => $maxbytes, 'accepted_types' => '*'));
$mform->addElement('filemanager', 'slidesyncslides', get_string('slidesyncslides', 'slidesync'), null, array('subdirs' => 0, 'maxbytes' => $maxbytes, 'maxfiles' => 50, 'accepted_types' => array('*') ));
after submit the files are stored in draft
and everything is loaded in another page that save all on db
if ($draftitemid = file_get_submitted_draft_itemid('slidesyncmedia')) {
file_save_draft_area_files($draftitemid, $context->id, 'mod_slidesync', 'slidesyncmedia', 0, array('subdirs' => 0, 'maxfiles' => 1));
}
if ($draftitemid = file_get_submitted_draft_itemid('slidesyncslides')) {
file_save_draft_area_files($draftitemid, $context->id, 'mod_slidesync', 'slidesyncslides', 0, array('subdirs' => 0, 'maxfiles' => 50));
}
in the end i use again the first page in another place (if files are there, then shows them)
$fs = get_file_storage();
if ($files = $fs->get_area_files($context->id, 'mod_slidesync', 'slidesyncslides', '0', 'sortorder', false)) {
// Look through each file being managed
foreach ($files as $file) {
// Build the File URL. Long process! But extremely accurate.
$fileurl = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
echo $fileurl;
}
} else {
echo '<p>Please upload an image first</p>';
}
this make an url but if clicked moodle says that file does not exist
mysite.com/pluginfile.php/53/mod_slidesync/slidesyncslides/0/Koala.jpg
in the db the file are correctly saved!!!
53 mod_slidesync slidesyncslides 0 / Koala.jpg
what i'm missing?
thanks
A long time passed but I was working on a plugin and had the same problem.
I manage to solve it.
To provide the file you need to create the:
function MYPLUGIN_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array())
Here is the example function: https://docs.moodle.org/dev/File_API#Serving_files_to_users
Remember change the last call to send_file to send_stored_file in Moodle 2.3+