Array to string conversion error in Yii2 console app - yii2

Please tell me such a thing. There is a self-written site, the code works on it, when I transfer the same code to the yii2 console application, it will get an error converting an array to a string
I will describe in more detail what is happening.
There is a text file inside which the following.
5|02.10.2020 20:20|Name 1
5|02.10.2020 22:25|Name 2
Day of the week, date and time, program name. It is necessary to add this case to the database.
$data = iconv("windows-1251", "UTF-8", file_get_contents( './import/' . $filename . '.txt' ) );
$tv = explode("\n", $data);
foreach ($tv as $line)
{
$ex1 = explode("|",$line);
$ex2 = explode(" ",$ex1[1]);
... next insert to db $ex1[0] - day of week, $ex2[0] - date, $ex2[1] - time, $ex1[2] - name
}
In a regular .php file, all this works, and when the same code is in yii2, it swears at conversion. Why is that? How to do it right?
It turns out that it cannot use $ ex1 [0], $ ex2 [0] and so on as a string.

Related

Reuse parameterized (prepared) SQL Query

i've coded an ActiveDirectory logging system a couple of years ago...
it never become a status greater than beta but its still in use...
i got an issue reported and found out what happening...
they are serveral filds in such an ActiveDirectory Event witch are UserInputs, so i've to validate them! -- of course i didnt...
so after the first user got the brilliant idea to use singlequotes in a specific foldername it crashed my scripts - easy injection possible...
so id like to make an update using prepared statements like im using in PHP and others.
Now this is a Powershell Script.. id like to do something like this:
$MySQL-OBJ.CommandText = "INSERT INTO `table-name` (i1,i2,i3) VALUES (#k1,#k2,#k3)"
$MySQL-OBJ.Parameters.AddWithValue("#k1","value 1")
$MySQL-OBJ.Parameters.AddWithValue("#k2","value 2")
$MySQL-OBJ.Parameters.AddWithValue("#k3","value 3")
$MySQL-OBJ.ExecuteNonQuery()
This would work fine - 1 times.
My Script runs endless as a Service and loops all within a while($true) loop.
Powershell clams about the param is already set...
Exception calling "AddWithValue" with "2" argument(s): "Parameter
'#k1' has already been defined."
how i can reset this "bind" without closing the database connection?
id like the leave the connection open because the script is faster without closing and opening the connections when a event is fired (10+ / sec)
Example Code
(shortend and not tested)
##start
function db_prepare(){
$MySqlConnection = New-Object MySql.Data.MySqlClient.MySqlConnection
$MySqlConnection.ConnectionString = "server=$MySQLServerName;user id=$Username;password=$Password;database=$MySQLDatenbankName;pooling=false"
$MySqlConnection.Open()
$MySqlCommand = New-Object MySql.Data.MySqlClient.MySqlCommand
$MySqlCommand.Connection = $MySqlConnection
$MySqlCommand.CommandText = "INSERT INTO `whatever` (col1,col2...) VALUES (#va1,#va2...)"
}
while($true){
if($MySqlConnection.State -eq 'closed'){ db_prepare() }
## do the event reading and data formating stuff
## bild some variables to set as sql param values
$MySQLCommand.Parameters.AddWithValue("#va1",$variable_for_1)
$MySQLCommand.Parameters.AddWithValue("#va2",$variable_for_2)
.
.
.
Try{ $MySqlCommand.ExecuteNonQuery() | Out-Null }
Catch{ <# error handling #> }
}
Change your logic so that the db_prepare() method initializes a MySql connection and a MySql command with parameters. Set the parameter values for pre-declared parameter names in loop. Like so,
function db_prepare(){
# ...
# Add named parameters
$MySQLCommand.Parameters.Add("#val1", <datatype>)
$MySQLCommand.Parameters.Add("#val2", <datatype>)
}
while($true) {
# ...
# Set values for the named parameters
$MySQLCommand.Parameters.SetParameter("#val1", <value>)
$MySQLCommand.Parameters.SetParameter("#val2", <value>)
$MySqlCommand.ExecuteNonQuery()
# ...
}

Accessing data retuned by PowerShell Import-CSV

I am trying to write a PowerShell script that uses a CSV file as input that will turn off the clutter feature in Office 365. The CSV file has only 1 column and that has the 2 target email addresses that I am using for testing. When I run this script with a read-host line and enter a valid email address it works with no errors. When I use the CSV file errors follow.
Import-Module MSOnline
$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/PowerShell -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession -allowclobber $Session
Connect-MsolService -Credential $LiveCred
cd c:\scripts
Write-Host "This tool removes the Clutter feature from O365 "
$Clutter = Import-Csv .\Clutteroff.csv
foreach ($user in $Clutter){
Set-Clutter -Identity $User -Enable $false
}
When I run this I get the following error :
Cannot process argument transformation on parameter 'Identity'. Cannot convert value "#{UserID=xxxxx#myCompany.com}" to type "Microsoft.Exchange.Configuration.Tasks.MailboxIdParameter". Error: "Cannot
convert hashtable to an object of the following type: Microsoft.Exchange.Configuration.Tasks.MailboxIdParameter. Hashtable-to-Object conversion is not supported in restricted language mode or a Data
section."
+ CategoryInfo : InvalidData: (:) [Set-Clutter], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-Clutter
+ PSComputerName : ps.outlook.com
Any help would be appreciated and explanations will get extra credit :)
CSV file = User, XXXX#MyCompany.com, YYYY#MyCompany.com
Email addresses are valid.
Putting all of the items in one line like that is not going to work well with Import-CSV. Import-CSV is suited to a table structure (columns and rows), whereas you are just using a comma-separated list (one row, with an unknown number of columns). If in fact you do have the items on different lines, then please correct the question and I'll change the answer.
To work with the data from a file formatted like that, I would just split it into an ArrayList, and remove the first item because it is "User" and not not an email address:
[System.Collections.ArrayList]$Clutter = (get-content .\Clutteroff.csv).split(",")
$Clutter.RemoveAt(0)
Then you can iterate through the array:
foreach ($user in $Clutter){
$address = $user.trim()
{Set-Clutter -Identity $address -Enable $false}
}
For the extra credit, $user in your script was returning a row of key/value pairs to represent columns (keys) and the data in the columns (values). Your error message shows #{UserID=xxxxx#myCompany.com}, so to return just the email address you would use $user.UserID to return the value for UserID.
i GOT THIS WORKING TO PULL FROM CSV SO ONLY THOSE USERS ARE MODIFIED!! SORRY FOR THE CAPS BUT I AM A TOTAL NOOB AND I COULDNT BELIEVE I GOT THIS TO WORK!!! I am beyond STOKED!! :)
the csv requires no headers, just the email address of the users you want to modify in one column
$Clutter = (Get-Content "pathofyourcsv.csv")
foreach ($User in $Clutter) {
$address = $User
Get-Mailbox -Identity $User | Set-Clutter -Enable $false}

Perl param() receiving from its own print HTML

I have a Perl script that reads in data from a database and prints out the result in HTML forms/tables. The form of each book also contains a submit button.
I want Perl to create a text file (or read into one already created) and print the title of the book that was inside the form submitted. But I can't seem to get param() to catch the submit action!
#!/usr/bin/perl -w
use warnings; # Allow for warnings to be sent if error's occur
use CGI; # Include CGI.pm module
use DBI;
use DBD::mysql; # Database data will come from mysql
my $dbh = DBI->connect('DBI:mysql:name?book_store', 'name', 'password')
or die("Could not make connection to database: $DBI::errstr"); # connect to the database with address and pass or return error
my $q = new CGI; # CGI object for basic stuff
my $ip = $q->remote_host(); # Get the user's ip
my $term = $q->param('searchterm'); # Set the search char to $term
$term =~ tr/A-Z/a-z/; # set all characters to lowercase for convenience of search
my $sql = '
SELECT *
FROM Books
WHERE Title LIKE ?
OR Description LIKE ?
OR Author LIKE ?
'; # Set the query string to search the database
my $sth = $dbh->prepare($sql); # Prepare to connect to the database
$sth->execute("%$term%", "%$term%", "%$term%")
or die "SQL Error: $DBI::errstr\n"; # Connect to the database or return an error
print $q->header;
print "<html>";
print "<body>";
print " <form name='book' action='bookcart.php' method=post> "; # Open a form for submitting the result of book selection
print "<table width=\"100%\" border=\"0\"> ";
my $title = $data[0];
my $desc = $data[1];
my $author = $data[2];
my $pub = $data[3];
my $isbn = $data[4];
my $photo = $data[5];
print "<tr> <td width=50%>Title: $title</td> <td width=50% rowspan=5><img src=$photo height=300px></td></tr><tr><td>Discreption Tags: $desc</td></tr><tr><td>Publication Date: $pub</td></tr><tr><td>Author: $author</td></tr><tr><td>ISBN: $isbn</td> </tr></table> <br>";
print "Add this to shopping cart:<input type='submit' name='submit' value='Add'>";
if ($q->param('submit')) {
open(FILE, ">>'$ip'.txt");
print FILE "$title\n";
close(FILE);
}
print "</form>"; # Close the form for submitting to shopping cart
You haven't used use strict, to force you to declare all your variables. This is a bad idea
You have used remote_host, which is the name of the client host system. Your server may not be able to resolve this value, in which case it will remain unset. If you want the IP address, use remote_addr
You have prepared and executed your SQL statement but have fetched no data from the query. You appear to expect the results to be in the array #data, but you haven't declared this array. You would have been told about this had you had use strict in effect
You have used the string '$ip'.txt for your file names so, if you were correctly using the IP address in stead of the host name, your files would look like '92.17.182.165'.txt. Do you really want the single quotes in there?
You don't check the status of your open call, so you have no idea whether the open succeeded, or the reason why it may have failed
I doubt if you have really spent the last 48 hours coding this. I think it is much more likely that you are throwing something together in a rush at the last minute, and using Stack Overflow to help you out of the hole you have dug for yourself.
Before asking for the aid of others you should at least use minimal good-practice coding methods such as applying use strict. You should also try your best to debug your code: it would have taken very little to find that $ip has the wrong value and #data is empty.
Use strict and warnings. You want to use strict for many reasons. A decent article on this is over at perlmonks, you can begin with this. Using strict and warnings
You don't necessarily need the following line, you are using DBI and can access mysql strictly with DBI.
use DBD::mysql;
Many of options are available with CGI, I would recommend reading the perldoc on this also based on user preferences and desired wants and needs.
I would not use the following:
my $q = new CGI;
# I would use as so..
my $q = CGI->new;
Use remote_addr instead of remote_host to retrieve your ip address.
The following line you are converting all uppercase to lowercase, unless it's a need to specifically read from your database with all lowercase, I find this useless.
$term =~ tr/A-Z/a-z/;
Next your $sql line, again user preference, but I would look into sprintf or using it directly inside your calls. Also you are trying to read an array of data that does not exist, where is the call to get back your data? I recommend reading the documentation for DBI also, many methods of returning your data. So you want your data back using an array for example...
Here is an untested example and hint to help get you started.
use strict;
use warnings;
use CGI qw( :standard );
use CGI::Carp qw( fatalsToBrowser ); # Track your syntax errors
use DBI;
# Get IP Address
my $ip = $ENV{'REMOTE_ADDR'};
# Get your query from param,
# I would also parse your data here
my $term = param('searchterm') || undef;
my $dbh = DBI->connect('DBI:mysql:db:host', 'user', 'pass',
{RaiseError => 1}) or die $DBI::errstr;
my $sql = sprintf ('SELECT * FROM Books WHERE Title LIKE %s
OR Description LIKE %s', $term, $term);
my $sth = $dbh->selectall_arrayref( $sql );
# Retrieve your result data from array ref and turn into
# a hash that has title for the key and a array ref to the data.
my %rows = ();
for my $i ( 0..$#{$sth} ) {
my ($title, $desc, $author, $pub, $isbn, $pic) = #{$sth->[$i]};
$rows{$title} = [ $desc, $author, $pub, $isbn, $pic ];
}
# Storing your table/column names
# in an array for mapping later.
my #cols;
$cols[0] = Tr(th('Title'), th('Desc'), th('Author'),
th('Published'), th('ISBN'), th('Photo'));
foreach (keys %rows) {
push #cols, Tr( td($_),
td($rows{$_}->[0]),
td($rows{$_}->[1]),
td($rows{$_}->[2]),
td($rows{$_}->[3]),
td(img({-src => $rows{$_}->[4]}));
}
print header,
start_html(-title => 'Example'),
start_form(-method => 'POST', -action => 'bookcart.php'), "\n",
table( {-border => undef, -width => '100%'}, #cols ),
submit(-name => 'Submit', -value => 'Add Entry'),
end_form,
end_html;
# Do something with if submit is clicked..
if ( param('Submit') ) {
......
}
This assumes that you're using the OO approach to CGI.pm, and that $q is the relevant object. This should work, assuming that you have $q = new CGI somewhere in your script.
Can you post the rest of the script?
I've created a mockup to test this, and it works as expected:
#!/usr/bin/perl
use CGI;
my $q = new CGI;
print $q->header;
print "<form><input type=submit name=submit value='add'></form>\n";
if ($q->param('submit')) {
print "submit is \"" . $q->param('submit') . "\"\n";
}
After the submit button is clicked, the page displays that submit is "add" which means the evaluation is going as planned.
I guess what you need to do is make sure that $q is your CGI object, and move forward from there.

Perl's REST Client error when trying to use Crontab

Script works well when run manually, but when I schdule it in cronjob it shows :
malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "<html>\r\n<head><tit...") at /usr/local/lib/perl5/site_perl/5.14.2/JSON.pm line 171.
script itself:
#rest config vaiables
$ENV{'PERL_LWP_SSL_VERIFY_NONE'} = 0;
print "test\n";
my $client = REST::Client->new();
$client->addHeader('Authorization', 'Basic YWRtaW46cmFyaXRhbg==');
$client->addHeader('content_type', 'application/json');
$client->addHeader('accept', 'application/json');
$client->setHost('http://10.10.10.10');
$client->setTimeout(1000);
$useragent = $client->getUseragent();
print "test\n";
#Getting racks by pod
$req = '/api/v2/racks?name_like=2t';
#print " rekvest {$req}\n";
$client->request('GET', qq($req));
$racks = from_json($client->responseContent());
$datadump = Dumper (from_json($client->responseContent()));
crontab -l
*/2 * * * * /usr/local/bin/perl /folder/api/2t.pl > /dmitry/api/damnitout 2>&1
Appreciate any suggestion
Thank you,
Dmitry
It is difficult to say what is really happening, but in my experience 99% issues of running stuff in crontab stems from differences in environment variables.
Typical way to debug this: in the beginning of your script add block like this:
foreach my $key (keys %ENV) {
print "$key = $ENV{$key}\n";
}
Run it in console, look at the output, save it in log file.
Now, repeat the same in crontab and save it into log file (you have already done that - this is good).
See if there is any difference in environment variables when trying to run it both ways and try to fix it. In Perl, probably easiest is to alter environment by changing %ENV. After all differences are sorted out, there is no reason for this to not work right.
Good luck!

perl eval throwing blank exception

I am updating a few records in database. And all the processing is done in eval block.
The problem is that even if the records are successfully updated , I still see a exception being raised.
To debug the exception, I tried printing it using Data Dumper but the exception is blank.
Can any one please help me identify what is this error and why is it thrown every time ?
Environment Details (Perl 5.8 and Unix SUSE)
Dump from Data Dumper:
$VAR1 = '
';
I am using various internal APIs, to update these records.. so I have modified my code to look similar:
sub main{
eval{
DB->updateRecord($value)
};
if($#){
Mail->SendMail(__PACKAGE__,$#):
}
}
package DB;
sub updateRecord{
my ($self , $value) = #_;
my $query = "update set column_value = $value ..<update query> ";
API->processQuery($query );
}
Does your code use warnings;?
The symptom your describing indicated that in your code you are passing die the string "\n". My guess would be that in your source you have a line that is trying to die with an error message but your error message was not initialized. It could be something like
my $error;
if (some_test()) {
$error = 'Some String';
}
if (some_other_test()) {
die "$error\n";
}
If some_test() passes but some_other_test() fails the die will report an error containing only a new line. It would also emit an warning if warnings are enabled.
Another possibility is a typo. If you don't use strict; the error variable might not be correct.
my $error = 'Some String';
if ($error) {
#note the typo (transposed ro to or)
die "$erorr\n";
}
Without use strict; this can be an easy mistake to miss.