How to extract all URL's from webpage in an array an see if certain value is there - arrays

I am trying to extract all the links from a webpage and put them into an array that I can then compare values with to see if there is a match. The problem that I'm having is I cannot seem to get the values into an array. I am able to see all the links and I see that there is a match with the one I'm trying to compare with but it's not recognizing that it's there. My code is as follows. Any help would be greatly appreciated.
$content = file_get_contents("sample_url");
$content = strip_tags($content, "<a>");
$subString = preg_split("/<\/a>/", $content);
$items = array();
foreach ( $subString as $val ){
if( strpos($val, "<a href=") !== FALSE ) {
$val = preg_replace("/.*<a\s+href=\"/sm", "", $val);
$val = preg_replace("/\".*/", "", $val);
$items[] = $val;
var_dump($val . "<br />");
}
}
if (in_array($testing_link, $items, true)) {
echo 'It is here!';
}
else {
echo 'it is NOT here :( ';
}

Better to use the DOMDocument to get the links into an array. Like this:
$doc = new DOMDocument();
// the string containing all the URLs and stuff
$doc->loadHTML($content);
//Extract the links from the HTML. From https://thisinterestsme.com/php-find-links-in-html/
$links = $doc->getElementsByTagName('a');
//Array that will contain our extracted links.
$extracted_links = array();
//Loop through the DOMNodeList.
//We can do this because the DOMNodeList object is traversable.
foreach ($links as $link) {
//Get the link text.
//$linkText = $link->nodeValue;
//Get the link in the href attribute.
$linkHref = $link->getAttribute('href');
}
Now all the HREFS are in the $linkHref array.
Better to use DOMDocument rather than RegEx. Much easier, and more accurate and consistent in results.

Related

Get array object data from exploded array fields in foreach loop

I'm trying to extract data from our JSON data based on given output fields, but I'm not getting a good result.
e.g.
Given fields that I want:
Array
(
[0] => id
[1] => name
[2] => email
[3] => optin_email
)
Those fields exist in my datastring, I want to export those to a CSV.
I can do this, hardcoded
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name,
$value->email,
$value->phone
];
print_r($row);
}
The above will give me the list/file I need. BUT, I want to make that dynamic based on the data in the array, so, fo rexample, when this is the Array:
Array
(
[0] => id
[1] => name
)
This should be my output:
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name
];
print_r($row);
}
So I need to dynamicly create the
$value->{var}
I have been trying forever, but I am not seeing it straight anymore.
Tried this:
$rowFields = '';
foreach ($export_datafields AS $v) {
$rowFields .= '$value->' . $v . ',';
}
$trimmed_row_fields = rtrim($rowFields, ',');
foreach ($jsonString as $value) {
$row = $trimmed_row_fields;
print_r($row);
}
And several variations of that:
foreach ($jsonString as $value) {
$row = [$trimmed_row_fields];
print_r($row);
}
Question is: how can I get
$value->VAR
as a valid array key when I only know the VAR name and need the prefixed $value-> object.
I ended up using the following code which works for me. If anybody still has the answer to my original question, please shoot. Always good to know it all.
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=$csvFileName");
header("Pragma: no-cache");
header("Expires: 0");
$new_row = implode(",", $export_datafields) . "\n";
foreach ($jsonString as $value) {
foreach ($export_datafields AS $v) {
$new_row .= $value->$v . ',';
}
$new_row = substr($new_row, 0, -1);
$new_row .= "\n";
}
echo $new_row;

How can i get top 15 occurrences in an array and use each value to fetch data from mysql database?

I am currently working on a project (A music website) with PHP Codeigniter. I want to fetch top 15 songs by number of downloads. To my knowledge, I got all unique ID's out ranging from highest to least. But now, I want to use each of these unique ID's to fetch data from another table in the database.
I have tried using for loop; but it seems to only return one of the rows which happens to be the first and highest number of occurrence in the array. The code below echo's the ID's but how can I use each of those ID's to fetch data.
function top15(){
$this->db->select('musiccode');
$result=$this->db->get('downloads');
$query = $result->result_array();
$downloads = array();
if(!empty($query)) {
foreach($query as $row)
{
$musiccode[] = $row['musiccode'];
}
$mode = array_count_values($musiccode);
arsort($mode);
$i = 0;
foreach ($mode as $field => $number) {
$i++;
echo $field." occured ". $number." times <br>";
if ($i == 15) {
break;
}
}
}
}
for ($b=0; $b < count($field); $b++) {
$this->db->where(array('track_musiccode'=> $field));
$field = $this->db->get('tracks');
return $field->result_array();
}
The code above only produce one row for me. I expect to have more than one and according to the number of ID's in the array. Thanks in advance.
For a single column condition, you could use where_in() instead and drop the for loop :
$this->db->where_in('track_musiccode', $field);
$field = $this->db->get('tracks');
return $field->result_array();
Yes Finally i did it. Incase if anyone needs it. this works just fine
function top15(){
$this->db->where('d_month', date('m'));
$this->db->select('musiccode');
$result=$this->db->get('downloads');
$query = $result->result_array();
$downloads = array();
if(!empty($query)) {
foreach($query as $row){
$musiccode[] = $row['musiccode'];
}
$res='';
$count=array_count_values($musiccode);
arsort($count);
$keys=array_keys($count);
for ($i=0; $i < count($keys); $i++) {
$res[] .= "$keys[$i]";
}
$this->db->where_in('track_musiccode', $res);
return $this->db->get('tracks')->result_array();
}
}
And I got this too. If I wasn't going to count occurrences but just iterate the number of downloads which is far more better than counting in other not to over populate the database and make your website work slowly.
function top15(){
$tracks = '';
$this->db->group_by('counter');
$result=$this->db->get('downloads');
$query = $result->result_array();
$counter = '';
$fields = '';
if(!empty($query)) {
foreach($query as $row) {
$counter[] = $row['counter'];
}
rsort($counter);
for ($i=0; $i<=15; $i++) {
$this->db->where('downloads.counter', $counter[$i]);
$this->db->join('tracks', 'tracks.musicid = downloads.musicid');
$fields[] = $this->db->get('downloads')->row_array();
}
return $fields;
}
}
Enjoy...

Find all in CakePHP is dumping a semicolon in my view

I don't know what exactly is happening with my CakePHP app. It worked last week and I have literally changed nothing with that particular file.
When I use find 'all' in my controller it dumps a semi-colon in my view even if there is nothing in the view file.
Here is my code
$evts = $this->Event->find('all');
There is nothing in my view file. I don't know if it makes a difference but I'm using a json view.
As requested here is the complete code for the action
public function search(){
$this->Event->recursive = 2;
$conditions = array();
if(!empty($this->request->query['name'])){
$conditions = array('Event.name LIKE ' => "%" . str_replace(" ","%", $this->request->query['name']) . "%");
}
if(!empty($this->request->query['home'])){
$conditions = array('Event.home_team_id' => $this->request->query['home']);
}
if(!empty($this->request->query['away'])){
$conditions = array('Event.away_team_id' => $this->request->query['away']);
}
$limit = 25;
if(!empty($this->request->query['limit'])){
$limit = $this->request->query['limit'];
}
//$evts = $this->Event->find('all',array('conditions'=>array($conditions),'order' => array('Event.start_time'),'limit'=>$limit));
$evts = $this->Event->find('all');
$this->set('events',$evts);
}
Everything in the view has been commented out ... but here is the code anyway
$results = array();
$i = 0;
foreach ($events as $event) {
$results[$i]['id'] = $event['Event']['id'];
$results[$i]['label'] = $event['Event']['name'] . "(" . date_format(date_create($event['Event']['start_time']), 'D, jS M Y') . ")";
$results[$i]['value'] = $event['Event']['name'];
$results[$i]['home_team_name'] = $event['HomeTeam']['name'];
$results[$i]['away_team_name'] = $event['AwayTeam']['name'];
$results[$i]['sport_name'] = $event['Sport']['name'];
$results[$i]['tournament_name'] = $event['Tournament']['name'];
$results[$i]['start_time'] = $event['Event']['start_time'];
$results[$i]['img'] = $event['Event']['img_path'];
$results[$i]['listener_count'] = 0; //TODO Get the follower count
$i++;
}
echo json_encode($results);
Display
If you changed nothing with that particular file then perhaps you have installed callbacks (either in the controller or in the model) that echo that ";". Look for 'afterFind' calls...
Search your model and your controller folders for "echo statement". In fact you should search your entire app folder except for the Views folder.

How can I convert validation error field names to input names in CakePHP?

I have a CakePHP (latest version) web app with forms and validation all working properly using traditional postback, but now I'm switching some of the forms to submit via ajax. When there are validation errors, I would like to get them back on the client as JSON formatted like so:
{
"success":false,
"errors":{
"data[User][username]":["This is not a valid e-mail address"],
"data[User][password]":["You must choose a password"]
}}
The keys for the errors array need to correspond to the name attribute on the form fields. We have some prebuilt client script that is expecting JSON formatted in this way. The good news is that this is very close to what the validationErrors object looks like in CakePHP. So I'm currently doing this in my controller:
if ($this->User->save($this->request->data)) {
} else {
if ($this->request->is('ajax')) {
$this->autoRender = $this->layout = false;
$response['success'] = false;
$response['errors'] = $this->User->validationErrors;
echo json_encode($response);
exit(0);
}
}
However, this is what the JSON response looks like:
{
"success":false,
"errors":{
"username":["This is not a valid e-mail address"],
"password":["You must choose a password"]
}}
Note that the errors keys have just the basic database table field names in them. They are not converted into data[User][username] format, which the FormHelper usually takes care of.
Is there some easy way to adjust the array before I return it? I don't want to simply loop through and prepend "data[User]" because that is not robust enough. I'd like some code I can put in one place and call from various controllers for various models. What does FormHelper use to come up with the input name attributes? Can I tap into that? Should I somehow use a JSON view?
That's because that's the way the $validationErrors array is formatted. To obtain the output you want you will have to loop through, there's no way around it.
foreach ($this->User->validationErrors as $field => $error) {
$this->User->validationErrors["data[User][$field]"] = $error;
unset($this->User->validationErrors[$field]);
}
I would suggest instead passing all errors to json_encode(). $this->validationErrors is a combined list of all model validation errors for that request available on the view (compiled after render). You should move your display logic (echoing json) into your view, and loop through it there.
in the view
$errors = array();
foreach ($this->validationErrors as $model => $modelErrors) {
foreach ($modelErrors as $field => $error) {
$errors["data[$model][$field]"] = $error;
}
}
$response['errors'] = $errors;
echo json_encode($response);
This would output something like this:
{
"success":false,
"errors": [
"data[User][username]": "This is not a valid e-mail address",
"data[User][password]": "This is not a valid password",
"data[Profile][name]": "Please fill in the field"
]
}
I have created a small recursive function to create validation error as a string with column name so that can be passed as json object.
/**
* prepare erorr message to be displayed from js
*
* #param array $errors validation error array
* #param stringn $message refernce variable
*
* #return void
*/
public function parseValidationErrors($errors, &$message)
{
foreach ($errors as $columnName => $error) {
$message .= "<strong>$columnName:</strong> ";
foreach ($error as $i => $msg) {
if (is_array($msg)) {
$this->_parseValidationErrors($msg, $message);
} else {
$message .= str_replace("This field", "", $msg . " ");
isset($error[$i + 1]) ? $message .= " and " : $message;
}
}
}
}
and controller code goes like this.
if (!$this->YourModel->saveAll($modelObject)) {
$errors = $this->YourModel->validationErrors;
$message = '';
$this->parseValidationErrors($errors, $message);
$response = array('status' => 'error', 'message' => $message);
}
$response['errors']['User'] = $this->User->validationErrors;

How do I use fixed fields in CakeDC's csvUpload behavior in Util plugin

I am using the csvUpload behavior of the Utils plugin by CakeDC, on a CakePHP 2.2.1 install.
I have it working great it's processing a rather large csv successfully. However there are two fields in my table / Model that would be considered fixed, as they are based on ID's from from associated models that are not consistent. So I need to get these fixed values via variables which is easy enough.
So my question is, how do I use the fixed fields aspect of csvUpload? I have tried that following and many little variation, which obviously didn't work.
public function upload_csv($Id = null) {
$unique_add = 69;
if ( $this->request->is('POST') ) {
$records_count = $this->Model->find( 'count' );
try {
$fixed = array('Model' => array('random_id' => $Id, 'unique_add' => $unique_add));
$this->Model->importCSV($this->request->data['Model']['CsvFile']['tmp_name'], $fixed);
} catch (Exception $e) {
$import_errors = $this->Model->getImportErrors();
$this->set( 'import_errors', $import_errors );
$this->Session->setFlash( __('Error Importing') . ' ' . $this->request->data['Model']['CsvFile']['name'] . ', ' . __('column name mismatch.') );
$this->redirect( array('action'=>'import') );
}
$new_records_count = $this->Model->find( 'count' ) - $records_count;
$this->Session->setFlash(__('Successfully imported') . ' ' . $new_records_count . ' records from ' . $this->request->data['Model']['CsvFile']['name'] );
$this->redirect(array('plugin'=>'usermgmt', 'controller'=>'users', 'action'=>'dashboard'));
}
}
Any help would be greatly appreciated as I have only found 1 post concerning this behavior when I searching...
I made my custom method to achieve the same task. Define the following method in app\Plugin\Utils\Model\Behavior
public function getCSVData(Model &$Model, $file, $fixed = array())
{
$settings = array(
'delimiter' => ',',
'enclosure' => '"',
'hasHeader' => true
);
$this->setup($Model, $settings);
$handle = new SplFileObject($file, 'rb');
$header = $this->_getHeader($Model, $handle);
$db = $Model->getDataSource();
$db->begin($Model);
$saved = array();
$data = array();
$i = 0;
while (($row = $this->_getCSVLine($Model, $handle)) !== false)
{
foreach ($header as $k => $col)
{
// get the data field from Model.field
$col = str_replace('.', '-', trim($col));
if (strpos($col, '.') !== false)
{
list($model,$field) = explode('.', $col);
$data[$i][$model][$field] = (isset($row[$k])) ? $row[$k] : '';
}
else
{
$col = str_replace(' ','_', $col);
$data[$i][$Model->alias][$col] = (isset($row[$k])) ? $row[$k] : '';
}
}
$is_valid_row = false;
foreach($data[$i][$Model->alias] as $col => $value )
{
if(!empty($data[$i][$Model->alias][$col]))
{
$is_valid_row = true;
}
}
if($is_valid_row == true)
{
$i++;
$data = Set::merge($data, $fixed);
}
else
{
unset($data[$i]);
}
}
return $data;
}
And you can use it using:
$csv_data = $this->Model->getCSVData($this->request->data['Model']['CsvFile']['tmp_name'], $fixed);
Here $csv_data will contain an array of all of those records from the csv file which are not empty and with the fixed field in each record index.
So as I was telling Arun, I answered my own question and figured it out. I was looking to broad instead of really examining what was in front of me. I started running some debugging and figured it out.
First of all, $unique_add = 69 is seen as an int, duh. In order for it to be added to the csv it need to viewed as a string. So it simply becomes, $unique_add = '69'.
I couldn't enter the value of $Id directly into the fixed array. So I just had to perform a simple find to get the value I needed.
$needed_id = $this->Model->find('first', array(
'condition'=>array('Model.id'=>$Id)
)
);
$random_id = $needed_id['Model']['id'];
Hopefully this won't be needed to help anyone because hopefully no one else will make this silly mistake. But one plus... Now there's actually more than one post on the internet documenting the use of fixed fields in the CakeDC Utils plugin.

Resources